68
79

More than 5 years have passed since last update.

Dockerで古いLAMPサーバーを稼働させたまま安全にアップグレードしよう

Last updated at Posted at 2016-03-25

やりたいこと

わりと古いLAMP(Linux / Apache / MySQL / PHP)サーバーが現役稼働中なのでアップグレードしたい、でも新しいサーバーを買う金は無い、どうしよう?という状況があり、Dockerを使えば安全に素早くアップグレードできるのではないかと思いついて、やってみました。

Dockerの導入

ここが一番難関です。古いサーバーにはDockerが導入できない場合があります。

以下面倒なのでrootで作業します。

Dockerのインストール

まずInstall Dockerを見てサーバー上にDockerをインストールします。Ubuntuの場合、64bitでカーネルのバージョンが3.10以上でないとインストールできないようです。

Dockerは以下の一行だけでインストールできました。

curl -fsSL https://get.docker.com/ | sh

確認

docker run hello-world

と入力してHello from Docker.以下ズラズラっとメッセージが表示されればOKです。

イメージ操作

以下のように入力すると現在のDockerイメージ一覧を確認できます。

docker images

出力例です。

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              690ed74de00f        5 months ago        960 B

先ほどのdocker runコマンドにより、Docker Hubからダウンロードされたhello-worldイメージが表示されています。

コンテナ操作

以下のように入力すると現在のDockerコンテナ一覧を確認できます。-aオプションは終了したコンテナも含めて表示します。

docker ps -a

出力例です。

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
0d000cf23953        hello-world         "/hello"            26 minutes ago      Exited (0) 26 minutes ago                       agitated_boyd

メッセージを表示してコンテナは終了しています。

不要なコンテナ&イメージの削除

hello-worldコンテナとイメージはもう不要なので消しましょう。

以下のコマンドでコンテナを消すことができます。

docker rm CONTAINER ID or NAMES

以下のコマンドでイメージを消すことができます。

docker rmi IMAGE ID or REPOSITORY:TAG

面倒なら以下のようにすると全てのコンテナとイメージを削除できます。

docker rm -f $(docker ps -a -q) && docker rmi -f $(docker images -a -q)

nginxコンテナの導入

元のWebサーバーはApacheでしたが、せっかくアップグレードするのでついでにカッコイイnginxにリプレースしてみましょう。

Docker Hubからnginxイメージをダウンロードしてコンテナを起動してみます。

docker run -p 8888:80 nginx

Webサーバーがフォアグラウンドで起動するのでコンソールは止まります。

コンテナ側では80番ポートでウェブサーバーが公開されます。ホスト側ではLAMPが稼働中で80番ポートは塞がっているので、-p 8888:80によって8888番ポートを公開するようにしています。

ブラウザでhttp://Webサーバーのホスト:8888/を開いてnginxの画面が表示されるか確認してください。コンソール画面にはnginxのアクセスログが表示されます。確認したらCtrl+Cで終了します。

Docker Composeの導入

続いてnginxコンテナとphpコンテナを連携させるのですが、Docker単体だと面倒なので、Docker Composeという複数コンテナを簡単に連携できるツールを使います。

Docker Composeのインストール

Install Docker Composeを参考にしてインストールします。以下の2行だけでいけました。

curl -L https://github.com/docker/compose/releases/download/1.6.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

定義ファイル用ディレクトリの作成

Docker Composeでは、いくつかの定義ファイルが必要になるので、ひとつ適当にディレクトリを作成します。場所はどこでも構いませんが、ディレクトリ名はコンテナ名のプレフィックスなどになるので気にしたほうが良いかもしれません。

以下、定義ファイル用のディレクトリを/root/lamp/とします。

mkdir /root/lamp
cd /root/lamp/

docker-compose.yml の作成

Docker Composeの定義ファイルを作ります。/root/lamp/に以下のファイルをdocker-compose.ymlという名前で作成してください。

docker-compose.yml
version: '2'
services:
  nginx:
    image: nginx
    ports:
      - '8888:80'

YAMLファイルなのでインデントは正確にしてください。

docker-compose.ymlの解説

    image: nginx

Docker Hubよりnginxイメージをダウンロードします。

    ports:
      - '8888:80'

コンテナ側のポート80番をホスト側ポート8888番で公開します。

Docker Composeの起動

docker-compose up

これでdocker-compose.ymlの定義に従ってコンテナが起動します。先ほどと同じようにブラウザでhttp://Webサーバーのホスト:8888/を開いてnginxの画面が表示されるか確認してください。確認したらCtrl+Cで終了します。

nginxコンテナとphpコンテナの連携

次に、Docker Composeを使ってnginxコンテナとphpコンテナを連携してみましょう。

Dockerfileを使ったnginxイメージのカスタマイズ

phpと連携するためにnginxイメージをカスタマイズします。Dockerfileを使うと既存のイメージをカスタマイズして新しいイメージを作成することができます。

docker-compose.yml

docker-compose.ymlを以下のように変更してください。

docker-compose.yml
version: '2'
services:
  nginx:
    build: ./nginx
    ports:
      - '8888:80'
    depends_on:
      - php
  php:
    image: php:fpm

docker-compose.ymlの解説

    build: ./nginx

nginxディレクトリにあるDockerfileを使いイメージを生成します。

    depends_on:
      - php

nginxサービスがphpサービスに依存していることを示しています。

  php:
    image: php:fpm

Docker Hubからphp-fpmイメージを取得しています。

nginx/Dockerfile

/root/lamp/内にnginxディレクトリを作成して、その中に以下のファイルを作成してください。

nginx/Dockerfile
FROM nginx
COPY default.conf /etc/nginx/conf.d/

nginx/Dockerfileの解説

FROM nginx

カスタマイズ元となるDocker Hubのイメージを指定します。

COPY default.conf /etc/nginx/conf.d/

新しく生成するイメージ内にファイルをコピーします。ここではnginxイメージに元々存在するdefault.confを上書きしています。

nginx/default.conf

/root/lamp/nginxディレクトリに以下のファイルを作成してください。

nginx/default.conf
server {
    listen       80;
    server_name  _;
    root   /usr/share/nginx/html;

    location / {
        index  index.html;
    }

    location ~ \.php$ {
        fastcgi_pass   php:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;
        include        fastcgi_params;
    }
}

もともと存在するdefault.confを上書きして、PHP-FPMとの連携を記述しています。

nginx/default.confの解説

        fastcgi_pass   php:9000;

この「php」というのはphp:fpmコンテナの内部アドレスです。Docker Networkという機能を使って名前解決しています。

        fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;

/var/www/html/のphpファイルを読みに行くようにしています。

起動

docker-compose up -d

-dオプションはバックグラウンドでコンテナを起動します。

コンテナ内にphpファイルを作成する

このままではphpファイルが無いので確認できません。そこで起動しているコンテナに入り、phpファイルを作成してみます。

まず起動しているコンテナを確認します。

docker ps

以下のような出力になります。

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                           NAMES
8b2c60187fac        php:fpm             "php-fpm"                3 minutes ago       Up 3 minutes        9000/tcp                        lamp_php_1
a6af857414c5        lamp_nginx          "nginx -g 'daemon off"   3 minutes ago       Up 3 minutes        443/tcp, 0.0.0.0:8888->80/tcp   lamp_nginx_1

最後のNAMESがコンテナ名です。
以下のコマンドでphpコンテナ内に入ります。

docker exec -ti lamp_php_1 bash

カレントディレクトリが/var/www/htmlであることを確認してphpファイルを作ります。

echo '<?php phpinfo();' > info.php

exitでコンテナから抜け、ブラウザでhttp://Webサーバーのホスト:8888/info.phpを開き、phpinfoの画面が表示されることを確認してください。

ホストのドキュメントルートディレクトリをコンテナにマウントする

以前のウェブサーバーは稼働中なので、ホスト側に/var/www/html等のドキュメントルートディレクトリがあると思います。そのディレクトリをコンテナにマウントしてみます。

docker-compose.yml
version: '2'
services:
  nginx:
    build: ./nginx
    ports:
      - '8888:80'
    depends_on:
      - php
    volumes:
      - /var/www/html:/usr/share/nginx/html
  php:
    image: php:fpm
    volumes:
      - /var/www/html:/var/www/html

volumesでホスト側のディレクトリをコンテナ側にマウントすることができます。再度

docker-compose up -d

して、ブラウザで開いて確認してみてください。

phpコンテナとmysqlコンテナの連携

同じようにして、mysqlコンテナを起動してphpコンテナからアクセスできるようにします。

docker-compose.yml

docker-compose.ymlを以下のように変更してください。

docker-compose.yml
version: '2'
services:
  nginx:
    build: ./nginx
    ports:
      - '8888:80'
    depends_on:
      - php
    volumes:
      - /var/www/html:/usr/share/nginx/html
  php:
    build: ./php
    depends_on:
      - mysql
    volumes:
      - /var/www/html:/var/www/html
  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: pass
    volumes:
      - db:/var/lib/mysql
volumes:
  db:

docker-compose.ymlの解説

    image: mysql

Docker Hubの公式のMySQLイメージを取得しています。

    environment:
      MYSQL_ROOT_PASSWORD: pass

rootのパスワードを「pass」に設定しています。

    volumes:
      - db:/var/lib/mysql

名前付きボリューム「db」にMySQLのデータが入るようにしています。

volumes:
  db:

名前付きボリューム「db」を定義しています。

ボリュームについて

ボリュームはコンテナとは分離されています。

docker volume ls

でボリューム一覧を表示します。上で定義した名前付きボリュームはlamp_dbという名前が付くと思いますので、

docker volume inspect lamp_db

で実体の場所が分かります。

php/Dockerfile

phpディレクトリを作成し、その中にDockerfileを作成してください。

Dockerfile
FROM php:fpm

RUN apt-get update \
  && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng12-dev libmcrypt-dev \
  && docker-php-ext-install pdo_mysql mysqli mbstring gd iconv mcrypt json ftp zip

必要そうなPHPの拡張機能を追加しています。

確認

コンテナを起動してphpからmysqlに接続できるか確認します。

docker-compose up -d

/var/www/html/test.php あたりに以下のようなファイルを作ってエラーが出なければ接続されているでしょう。

<?php new PDO('mysql:host=mysql;dbname=mysql', 'root', 'pass');

ホスト名が「mysql」になることに注意してください。

本番サーバーのリプレース

上記の設定にさらに細かい設定を追加したものが以下になります。

こちらを元に本番サーバーをリプレースしてみましょう。

その前に、ポート8888番で本番同様に動くことをしっかり確認しておきます。
また、MySQLの認証や、phpinfo等の不要なファイルを消すなど、セキュリティ対策をしっかり行ってください。

ポートを変更する

docker-compose.yml

    ports:
      - '8888:80'

これを

    ports:
      - '80:80'

と変更します。

Webサーバーを止める

ここからはスピード勝負になります。

例えばAPTでインストールしたなら以下のようにして止め、80番ポートを開放します。

service apache2 stop

データベースのバックアップ

元のデータベースをmysqldumpなどでバックアップします。

コンテナを再起動する

docker-compose up -d

でコンテナを再起動します。

データベースのリストア

データベースをリストアします。

確認する

元のURLでサイトの不具合がないことを確認する。

最後に

Dockerを使えば一台のサーバーでもほぼダウンタイム無しでアップグレードできました。

68
79
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
68
79