Dockerで開発環境

pythonやphpのバージョンで悩む

Dockerとは

pythonやphpで開発するときに、使用するライブラリーの関係で現在入れているバージョンではできなことが時々あります

パソコンが複数台あれば専用機を作って試すとかできますが、もったいない。pythonなら環境をコマンドで切り替えもできますが、面倒。そこでDockerを使ってなんとかならないか試してみました

Dockerの準備

Dockerはコンテナ仮想化技術を使って、作りたい環境をコンテナの中に作って、複数のコンテナの中に複数の環境をバーチャルに作ってしまうものを簡単に扱えるようにしたソフトウェアです。

dockerとは

一般的にはOSの上にアプリが乗りますが、これだと環境設定は切り替えはできても同時に使える環境はいづれか1つになります。ホスト型ではOSの上にホスト型仮想化のソフトウェアを入れて、その中にゲストOSを別に入れます。環境を複数作れますがソフトウェアでシミュレートしている感じです。

そこでハイパーバイザーの中にOSを複数入れられるようにする方法ができました。この方がさくさく動きます。そしてDockerですが、黒枠の中がコンテナで、そこに環境とプログラムが入ります。WindowsのDockerの場合はWSL2またはハイパーバイザーを借りることになります。Dockerはlinuxのディストリビューションではなくcoreを使用します

似たようなもんじゃないかと思わるかもしれませんが、Dockerの良いところは、すぐ消せることです。失敗してもすぐ消して、修正して、すぐ始められる。なにせOSのインストールは初回の1回だけですみますから。

Dockerを行う手順 - Windowsの場合

Docker Desktopのダウンロード
www.docker.comにいってdocker desktopをダウンロードします
Docker Desktopのインストール
インストールする過程で自動でWSL2が使えるようになります
再起動とセットアップ
再起動後セットアップ作業をします
最初の起動とアンケート
最初の起動でサインインを求められますが必須ではありません。何に使うか答えます
空のコンテナが表示されます
これで準備完了です

Dockerのダウンロード

www.docker.comに行きます。

docker download

青いdownloadのボタンにマウスをかざすと、OSの種類を聞いてきますので、それぞれ選んでください。Windowsであれば windowsのAMD64です。

select os

Docker Desktopのインストール

ダウンロードフォルダーに「Docker Desktop Installer.exe」があります。以前のインストールでは先にWSL2を有効にする作業が必要でしたが、現在のバージョンではインストールの工程で自動的にその作業もしてくれるので、そのままインストールしてください。

Installer.exeをダブルクリックします。アカウント制御の画面が出たら「はい」をクリックします。同様のものがもう一回出るかもしれませんがそれも「はい」です。

そしてDockerの特徴であるLinuxのCoreをどこから使うかの質問が出ます。
「Use WSL2 instead of Hyper-V(recommended)」(Hyper-VよりもWSL2の方をお勧めします)
「Add shortcut to desktop」(デスクトップにショートカットを作りましょうか?)
の両方にチェックを入れて「OK」を押してください

wsl2

「Installation succeeded」と表示されたらインストール修了です。「Close And Restart」を押して再起動してください

restart

再起動とセットアップ

パソコンを再起動すると「Docker Subscription Service Agreement」の画面が表示されます。実はDockerは個人使用や中小企業は無料ですが、それ以外は有料です。我々は教育用ですので無料で行います。「Accept」をクリックして承諾してください。

docker start

次の画面でWSL2の自動更新のままでよいので「Finish」をクリックします

最初の起動とアンケート

そして最初のDocker Desktopの起動になりますが、Sign Upを求められますが必須ではありません。「Continue without signing in」をクリックしてください。

sign in

アンケートで、お仕事は何ですか?と聞かれます

role

最後に「Tell us about the work you do」(どんなことにお使いですか?)と聞いてきます。私は「Learning or teaching」にしました。で「Continue」をクリックします

role

空のコンテナが表示されます

ようやく空っぽのコンテナが表示されたと思います

first docker

これで準備OKです

Dockerで色々な環境を作る

Dockerに入れるようなものは大体決まっていますので、そういうものをDockerがDocker HubというWeb上のサイトに載せてくれています。それをimageといいます。

われわれの作業はそのimageを選んで「Pull」(download)してDockerを使って「Continer」(コンテナ)に環境を作り「Run」(実行)するのです

コンテナはそれぞれ独立していますので、ほかの設定が邪魔することはありません。しかし、その分だけ領域は使用します。

また今表示されているDocker Desktopは操作パネルであって、細かい設定をしたりするものではありません。どのimageを使うのか、同様な設定にするかは設定ファイルをいくつか作って、それをコマンドプロンプトでコマンドを手入力して操作します。

デスクトップの左側に上から「コンテナ」「イメージ」「ボリューム」「ビルド」のアイコンが並んでいます。Docker HubからPullしたものがイメージに保存されます。いらなくなれば消せます。そのイメージをRunすると「コンテナ」に表示されます。これも使い終わったら消せます。設定ファイルは適当なフォルダーの中にそれぞれ作ります。そしてそのフォルダー内でコマンドプロンプトを実行するのです。

たとえばHTMLファイルや作成したデータベースなど、取っておいて使いたいものがあると思いますが、何もしないとそれらのデータは消去で消えてしまいます。そこで「ボリューム」を設定ファイルで宣言すると、Dockerのバーチャル空間のファイルがそれぞれのフォルダーの中に同期して残り、再利用ができるようになります。apacheなどでpublic_htmlフォルダーにftpで送るのと同じように指定したフォルダー内に/srcなどのフォルダーにindex.htmlなどを入れておけば、同期してくれるのです。

設定ファイルでイメージを作るには、言語コンパイラと同じようにビルドを行います。その履歴が「ビルド」に入ります。ビルドが失敗すると実行できませんので履歴のエラーログをみて修正してください。

apache環境を作ってみる

ではまず単純にapacheつまりhttpdのイメージをPullして、index.htmlを表示するだけのコンテナを作ってみましょう。

たとえばドキュメントフォルダーにdockerフォルダーがあるとして、apache実験用のフォルダーと設定ファイルを作ります

apache実験
    > mkdir apachetest
    > cd apachetest
    

そのフォルダーにcompose.yamlを作ります

compose.yaml
services:
  web:
    image: httpd:2.4
    ports:
      - "8000:80"
    volumes:
      - ./src:/usr/local/apache2/htdocs

このyamlファイル、インデントが重要です。左端から始まり、次のインデントはスペース2つです。なのでweb:は2つスペースを入力してから書き始めます。次の行のimageは4つスペース。:の後ろは1つスペースを入れてhttpdです。間違えると動きません。

よくサンプルサイトで全部インデント0に表示されているのがありますが、意図と違います

webはサービス名、httpdがDocker Hub上のimage名で:2.4がバージョンです。portsがポートでapacheの80ポートを8000ポートにフォワードすることになります。 volumesは以下に作ったsrcフォルダーを同期しますよという意味です。この/usr/localはあくまでもバーチャルで作成したシステムの中でのフォルダーなので、ubuntuに切り替えてみてもそこにはありません。コンテナが動いているとき/srcの中身を書き換えると同期されます。ftpのようにコピーする必要はありません。

compose.yamlのサンプルをネット上で検索するとdocker-compose.ymlが表示されることが多いですが、それはバージョンが古いです。しかし先頭のversion:以外は大体使えるのでそれでもかまいません。

srcフォルダーを配下に作りindex.htmlを入れます。なんでもいいです

./src/index.html
    <html><body><h1>Congratulations. apache working</h1></body></html>

そしてDockerのコマンドを入力します

実行コマンド
    > docker compose up -d 

composeがcompose.yamlを使って環境を整えてくれるツールで、upすることでビルドして実行までしてくれます。-dがついていると、実行してすぐにコマンドプロンプトに戻て来てくれます。つけないと実行中は次のコマンドが入力できなくなります。

apache build

これでDocker Desktopのコンテナをみると、runしているのがわかります

ここでこのコマンドをいれてエラーになった場合、

コマンドでエラー発生
    > docker compose up -d
error during connect: Get "http://%2F%2F.%2Fpipe%2FdockerDesktopLinuxEngine/v1.46/containers/json?all=1&filters=%7B%22
label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dapachetest%22%3Atrue%7D%7D": 
open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.

これはDocker Desktopを起動していない時で、Docker engineが動いていないのです。Docker desktopを起動してからやってください。

container running

失敗しているとrunningにならずExitedなどになっています。compose.yamlはちょっとでも間違えると動かないので気を付けましょう

さて、apacheは起動されたでしょうか。ブラウザを立ち上げて「localhost:8000」に接続します

apache work

動きましたか?

では、この現在動いているコンテナの中に入ってみましょう。コンテナはバーチャルですが、runningの今は接続できます。

コンテナに接続
    > docker compose exec web /bin/bash 

composeのexecコマンドでcompose.yamlで指定したサービス名を記述、コマンドラインを呼び出します

exec container

コンテナに接続して、apacheのhtdocsの中身が同期されておるのがわかったでしょうか

接続を終了するときは

接続の終了
    # exit

「exit」と入力してコマンドプロンプトに戻ります

続いて、コンテナの終了です

コンテナの終了
    > docker compose down

これでコンテナは終了します。使い終わったら消すのがお作法です

delete container

コンテナは消しましたが、imageは残っています。なのでまた upすればすぐにコンテナを再生できます。

imageも消したい場合は

イメージの削除
    > docker images -a
    > docker rmi {IMAGE ID}
delete image

コンテナを削除するときにimageも一緒に消したい場合は

コンテナとイメージの削除
    > docker compose down --rmi all 
delete container and image

xampp環境を作ってみる

いままでphpやデータベースを学習するのに「xampp」を使っていました。しかしphp7を勉強しようとしたら最新のxamppはphp8になっていたり、少し設定がおかしくて動きがおかしいなんてことはざらにあります。

そこでxamppの代わりにdockerが使えないか試してみました。まずはphp8バージョンです

もう細かいことは抜きでファイルの説明だけします。自分でやってみてください

postxamppのファイル構成
postxampp
  compose.yaml
  Dockerfile
  +--src
     dbsample.php
     phpinfo.php

ここにDockerfileというものが登場しました。Dockerfileはcompose.yamlで作ったコンテナの中での追加設定やバージョンの指定をあらかじめ書いておく設定ファイルです

compose.yaml
services:
  db:
    image: mariadb:10.7
    environment:
      MARIADB_ROOT_PASSWORD: rootpass
      MARIADB_DATABASE: testdb
      MARIADB_USER: testuser
      MARIADB_PASSWORD: testpass
    volumes:
      - db-data:/var/lib/mysql
  phpmyadmin:
    image: phpmyadmin:5.2
    depends_on:
      - db
    environment:
      PMA_HOST: db
      PMA_USER: testuser
      PMA_PASSWORD: testpass
    ports:
      - "8080:80"
    volumes:
      - phpmyadmin-data:/sessions
  apache:
    build: .
    depends_on:
      - db
    container_name: 'apache'
    ports:
      - "8000:80"
    volumes:
      - ./src:/var/www/html
volumes:
  db-data:
  phpmyadmin-data:

サービスが3つ。dbとphpmyadminとapacheです。インデントはすべてスペース2つでやっています。間違うと動きません。

phpmyadminのportを8080にして、apacheを8000にして、htdocsを/var/www/htmlにしています。

Dockerfile
FROM php:8.0-apache
RUN apt-get update && apt-get install -y libonig-dev && docker-php-ext-install pdo_mysql

php8を使用し必要なライブラリーを取り込んでいます。他に必要なものがあれば追加しておけばすぐに使用できます。ここに書いてなくてもコンテナにexecで接続して追加はできます

src/dbsample.php
    <?php
    try {
        $dsn = 'mysql:host=db;dbname:testdb;';
        $db = new PDO($dsn, 'testuser', 'testpass');
        echo "接続に成功しました";
    } catch (PDOException $e) {
        echo "接続に失敗しました";
        echo $e->getMessage();
        exit();
    }
    ?>

またphpのバージョンをチェックするために、phpinfoを実行します

src/phpinfo.php
    <?php
    phpinfo();
    ?>

では「docker compose up -d」でコンテナを実行して、つないでみましょう。「localhost:8000/dbsample.php」です

データベース接続サンプル

またphpバージョンのチェックです。「localhost:8000/phpinfo.php」で見てみましょう

phpバージョンチェック

phpmyadminもチェックしましょう。portを8080にしておいたので「localhost:8080」です

phpmyadmin

できましたか?では今度はphp7をやってみましょう。一度コンテナもイメージも消しておきましょう

php7にするには、Dockerfileを書き換えるだけです

Dockerfile
FROM php:7.4-apache
RUN apt-get update && apt-get install -y libonig-dev && docker-php-ext-install pdo_mysql
php7

php7で動いていますね

pythonの2と3を作ってみる

phpの切り替えができましたのでpythonでやってみましょう

pytestのファイル構成
pytest
  compose.yaml
  Dockerfile
  +--opt
     sample.py

compose.yamlやDockerfileは同じように作り/optフォルダーにサンプルプログラムを入れます

compose.yaml
services:
  python3:
    restart: always
    build: .
    container_name: 'python3'
    working_dir: '/root/'
    tty: true
    volumes:
      - ./opt:/root/opt
Dockerfile
FROM python:3
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN apt-get install -y vim less
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools

python3を指定して、環境編巣も設定しておきます

「docker compose up -d」でコンテナを作りましょう。

python3

またコンテナに接続してpython3を実行してみましょう

python3

ではpython2に切り替えましょう

phpの時と同じように設定ファイルをさわります

compose.yamlやDockerfileは同じように作り/optフォルダーにサンプルプログラムを入れます

compose.yaml
services:
  python2:
    restart: always
    build: .
    container_name: 'python2'
    working_dir: '/root/'
    tty: true
    volumes:
      - ./opt:/root/opt
Dockerfile
FROM python:2
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN apt-get install -y vim less
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools

python2を実行します

python3

これで両方の環境で実行ができますね