DockerfileでPHP7環境構築
今回、Docker HubにあるPHP公式リポジトリのCreate a Dockerfile in your PHP projectの部分を参考にしました。
環境
mac OS Sierra上にDocker for macでPHP7 + apacheの環境を構築していきます。今はnginxが主流となりつつありますが、トラブルシューティングしやすいように、今回は慣れているapacheを使います。
- Docker version 17.06.1-ce
ディレクトリ構造
php7testというディレクトリのなかに以下の3つのファイルを作成
Dockerfile
FROM php:7.0-apache MAINTAINER username COPY config/php.ini /usr/local/etc/php/ COPY src/ /var/www/html/
Dockerfileをビルドすることで、オリジナルのイメージを作成することができます。
FROM php:7.0-apache
は、公式のphp:7.0-apache
というイメージを取得する、という意味です。まずイメージを取得し、それのイメージに新しく情報をつけ加えてきます。プログラミング的には、継承の感覚に近いかもしれません。このイメージを取得した時点で、PHP7 とapacheは入っているということです。
MAINTAINER username
はDockerfileの製作者です。自身の名前を入れれば良いですが、必要なければカットしても良い情報です。
COPY config/php.ini /usr/local/etc/php/
では、config
ディレクトリ内につくったオリジナルのPHP設定ファイルを、後々つくられるコンテナ側のOSの/usr/local/etc/php/
下にコピーします。
COPY src/ /var/www/html/
も同じようなものですね。
これで、一度イメージをビルドすれば、コンテナ作成 →動作確認→コンテナ破棄→ホスト側ファイルの修正→コンテナ作成→動作確認のサイクルを確立できます。(srcファイル下であれば、ですが)
src/index.php
<?php phpinfo();
入っているPHPの情報をざっと確認したならこれですよね。
config/php.ini
date.timezone = "Asia/Tokyo"
PHPの設定ファイルです。最初は少しだけの情報にして、上手くいったら追加の設定を書き込んでいくのが安全です。
ビルド
Dockerfileが存在するディレクトリ下でコマンドを実行していきます。
docker build -t php7test .
php7test
の部分はイメージ名です。つけたいイメージ名を書いてください。.
をつけ忘れないようにしましょう。
終了したら、docker images
でイメージが作成された確認しておきます。
ホスト側のブラウザで確認
docker run -v /Users/yourname/php7test/src/:/var/www/html -d -p 8000:80 --name php7cont php7test
php7testというイメージからphp7contというコンテナを作成しています。(コンテナ名を付ける場合は--name
が必要)
docker ps -a
で上手くいっているかチェックしておきます。
PORTS
は0.0.0.0:8000->80/tcp
となっているでしょうか。0.0.0.0
とはlocalhost
のことですね。
http://localhost:8000
にアクセスするとPHPの情報が表示されるはずです。バージョン7が入っていれば成功です。
ネット上の情報をみていると、localhostではダメな場合もあるようで、その場合は次のように、IPアドレスで指定するようですね。 (たぶん、dockerとホストのあいだにvagrantとかを挟んでいるのが原因)
IPアドレス:8000
IPアドレスはifconfig
コマンドで調べることができます。
肝心のコマンドが長いですが、分解すると見えてきます。
1. ホスト・コンテナ間でファイルを共有
docker run -v ホスト側パス:コンテナ側パス
なぜか僕の環境ではホスト側のパスだけフルパスで書かないと上手くいきませんでした。上手くいかないときは試してみてください。
2. コンテナ側のポートをホストでも使えるようにする(ポートフォワード)
docker run -p ホスト側ポート:コンテナ側ポート
3. デタッチモードでコンテナ起動(バックグラウンドで動作)
docker run -d イメージ
php.iniの設定が反映されているか確認
phpinfoで表示した部分をチェックしておきます。
デフォルトのタイムゾーンがAsia/Tokyo
になっていますね。上手くいっているみたいです。
今度イメージを作成するときは、ほかの設定もいじってみましょう。
サイクル体感
docker stop コンテナ名(コンテナID)
でコンテナを停止できます。
docker rm コンテナ名(コンテナID)
でコンテナを削除できます。
src/index.php
を書き換えて、もう一度docker run ~
を実行してみましょう。
ブラウザに書き換えたindex.php
の内容が表示されれば、Dockerによる開発サイクルを実感できるはずです。
参考
Docker for MacでPython3環境の構築
きっかけ
仕事ではPHPとか、javascriptとかばっかりいじっているので、プライベートでは仕事で使う以外の言語でなにかつくったりしよう(遊ぼう)と思い立ったのが2ヶ月前くらいでした。
「機械学習とか流行ってたなあ。出来たら面白そうだなあ。日本ではそれほどだけど、世界的なシェアはかなりある言語だから、まあやって損はないかな」なんて安直な理由でPythonを勉強しはじめました。
あくまで趣味の範囲なので、Macに最初から入っている2系のPythonを使っていました。しかし、ネットに落ちている情報などを見ていると、3系のPythonで書かれたソースコードが多くなってきているように感じます。いちいち2系と3系の違いを意識しながらプログラミングするのは面倒です。
しかし、趣味の範囲と言えど、3系のPythonを直接Macに落とし込むのは2系のPythonとバッティングしそうでなんとなく怖い。
というわけでDockerで仮想環境を立てることにしました。
Docker for Mac
下のリンクからダウンロードできます。僕は安定版(Stable)の方を入れました。
ダウンロードが終了したら起動しましょう。
ターミナルからバージョンを確認しておきます。
$ docker --version Docker version 17.06.1-ce, build 874a737 $ which docker /usr/local/bin/docker
Docker Hubから公式イメージを入手
Docker Hubというサイトで、どのようなイメージが配布されているかチェックできます。イメージをpullしてくるだけなら登録は必要ないです。
Official(公式)のものがあったので、そのイメージを利用することにします。
上のリンクにも書いてあるのですが、docker pull python:<バージョン>
のようにして、バージョン指定を行うことができます。今回は3.6を取得します。
sudo docker pull python:3.6
入れたらdocker images
で確認しておきます。
REPOSITORY TAG ... python 3.6 ...
ほかにもIMAGE_ID
やSIZE
を見ることができるはずです。
コンテナ起動
docker run -it
でコンテナを作成し、操作できます。ここでは後につづく/bin/bash
でログインしています。
--name 名前
でコンテナに名前をつけることもできます。ここではpytest
のことを指します。
docker run -it --name pytest python:3.6 /bin/bash
入ることに成功したら、Linuxディストリビューションの情報を確認してみます。
/etc/ディストリビューション名-release
か/etc/issue
のどちらかのファイルを見てましょう。
OSのバージョンを確認するにはuname -a
コマンドを使います。
# cat /etc/os-release PRETTY_NAME="Debian GNU/Linux 8 (jessie)" NAME="Debian GNU/Linux" VERSION_ID="8" VERSION="8 (jessie)" ID=debian HOME_URL="http://www.debian.org/" SUPPORT_URL="http://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/" # cat /etc/issue Debian GNU/Linux 8 \n \l # uname -a Linux 0823c3a40902 4.9.41-moby #1 SMP Fri Aug 18 01:58:38 UTC 2017 x86_64 GNU/Linux
pythonのバージョンを確認すると、ちゃんと3.6が入っています。
# python --version Python 3.6.2
pythonを管理するのに便利なpip
も入っていました。ありがたい。
# pip --version pip 9.0.1 from /usr/local/lib/python3.6/site-packages (python 3.6)
Pythonを動かしてみる
僕の場合、エディタもなにも入っていなかったので、とりあえずVimを落としてきました。Emacs派の人はEmacsを、どちらもわからない人はnanoあたりをインストールしてきて使いましょう。
ちなみに、最初にapt-get update
は実行しないとapt-get
が使えないようです。
sudo
コマンドも入っていなかったのでrootユーザのままでエディタをインストールします。
# apt-get update # apt-get install -y vim
rootユーザのままだと落ち着かないので、新しくユーザをつくって、そのユーザで操作することにします。
# useradd -m pytest
上記コマンドで新規ユーザを登録できます。オプション-m
は/home
にユーザを作成することを指示します。このオプションをつけないとどこにユーザがつくられるかわかりません。
ls /home
でpytest
が追加されていることを確認したらsu pytest
でpytestユーザになります。変わることができたかは、コマンドライン上の#
が$
になったかならないかで判断できます。
su - pytest
のようにコマンドを実行すると、一発でpytestのホームディレクトリまで移動してくれます。
/home/pytest/
にまで移動し、そこでhello.py
を作成します。
#-*- coding: utf-8 -*- print("hello, python3")
python hello.py
で実行し、文字列が出力されればオーケイです。
※2017.09.10追記
そのままの設定だと、rootユーザでないとファイル編集できないみたいです。(Permission denied)自分はこのファイルをつくったときtootでなかったような気がするのですが、実際新しくファイルを作成してみると「rootでないとダメ」とメッセージが表示されました。ファイル作成の際は、rootユーザの状態で行ってください。
※2017.09.14追記
スミマセン、上記の件ですが、普通にいろいろいじっていただけで勘違いでした。pytestユーザでもファイルを作成できることを確認しました。
終了するには
1回目のexit
でルートユーザに戻り、2回目のexit
でホスト環境へ戻ってきます。
コンテナの起動・停止
docker ps -a
により、停止しているコンテナも表示することができるのですが、上記までの流れをそのままやってみると、コンテナは自動的に停止しています。(STATUS項目にExitedと表示されていれば停止しています)
コンテナを起動するにはdocker start コンテナID
、もしくはdocker start コンテナ名
を使います。
docker start pytest
もう一度docker ps -a
で確かめると動いているのが確認できるはずです。(その場合ExitedがUpになっている) 稼働しているので、a
オプションをつけなくても表示されます。
停止するには、docker stop コンテナID
、またはdocker stop コンテナ名
です。
docker stop pytest
もう一度ログインする
もう一度コンテナ内に入るためにはdocker exec
を使います。動作中のコンテナでコマンドを実行するコマンドです。裏を返せば停止してるコンテナは操作できないということです。
docker exec -it pytest /bin/bash
入ることができたら作成したhello.py
があることを確認してみましょう。
ホストから編集・実行
お気づきの方もいるかもしれませんが、hello.py
があるか確認するだけならば、docker exec
を使えばコンテナ内に潜る必要はありません。
docker exec -it pytest ls /home/pytest
pytestコンテナに「lsコマンドを実行せよ」と命令を出しています。ここではhello.py
を作成した/home/pytest
下を見ています。
ということは、このようなこともできるわけです。
docker exec -it pytest vim /home/pytest/hello.py
軽く編集してみます。
#-*- coding: utf-8 -*- print("hello, python3") print("hello, docker!!")
execで実行。
docker exec -it pytest python /home/pytest/hello.py
追加した文字列がホストのターミナルに出力されるかと思います。
2017.09.10追記
上記のように
docker exec -it pytest python /home/pytest/hello.py
など、ホスト側でpythonを実行したとき、エラーではないけれど変な感じで出力されるときがあるかと思います。
そういう場合は、Ctrl + l
などで一度ターミナルをクリアしてから、もう一度プログラムを実行すると、上手く出力される
可能性があります。
また
docker exec -it pytest python
とすることでpythonの対話モードが呼び出せることも確認しました。ちょっとした確認ならば、こちらを使う方が良いでしょう。
参考
- 目指せ文系からの一流エンジニア!初心者のDocker勉強会
- Dockerでpython3環境を準備する
- よく使うDockerコマンド
- Dockerコンテナの作成、起動〜停止まで
- Linux ディストリビューション・バージョンの確認方法
Milkcocoaを使って簡易チャットを制作
前提
- Google Chromeでしかテストしていません
Milkcocoaってなに?
Uhuru社から提供されているBaaS(Backend as a Service)です。
Baasというのは、「自分でサーバを用意して、データベースを入れて〜」というような一連の環境構築をする必要がなく、さらに、ある程度のサーバサイドの機能(データ管理、プッシュ通知など)を用意してくれているので、フロントエンドの開発だけに集中できるサービスです。
立ち位置としては、SaaSとPaaSの中間くらいです。
メールアドレスとパスワードの登録だけで始められるので手軽です。クレジットカードの登録なんか要りません。
また日本発のサービスなのでドキュメントが日本語。英語が苦手な僕にとってはありがたかったです。
簡易チャット作成
今回はjavascriptで適当にチャットアプリをつくってみます。
index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Milkcocoa</title> <script src="https://cdn.mlkcca.com/v0.6.0/milkcocoa.js"></script> <script src="main.js"></script> </head> <body> <textarea id="messageArea" style="width:300px;height:150px;background:#555;color:#fff;font-size:17px;"></textarea><br> <button onclick="pushData()" style="width:150px;height:30px;">データを追加</button> <button onclick="pullData()" style="width:150px;height:30px;">データを取得</button> <ul id="pullDataArea"> </ul> </body> </html>
main.js
var milkcocoa = new MilkCocoa('app_id'); var chatDataStore = milkcocoa.dataStore("chat"); var textArea, ul; /** * ロード時処理 * 5件のデータを読み込む */ window.onload = function() { textArea = document.getElementById("messageArea"); ul = document.getElementById('pullDataArea'); getText(); } /** * pushされたとき、新しいデータを引っ張ってくる(pushされる状態を監視) */ chatDataStore.on("push", function(data) { pullData(); }); /** * データ追加ボタンを押された時の処理 */ function pushData() { var text = textArea.value; sendText(text); } /** * データをデータストアに追加し、テキストエリアは空にする * @param text データストアに追加するテキスト */ function sendText(text) { chatDataStore.push({message: text}, function(data) {}); textArea.value = ""; } /** * データ取得ボタンを押された時の処理 * テキスト送信時の更新 */ function pullData() { removePullData(); getText(); } /** * 新しい順に5つデータを取得 */ function getText() { chatDataStore.stream().size(5).sort('desc').next(function(err, data) { addPullData(data); }); } /** * 取得したデータを画面上に表示する * @param data 取得したデータ */ function addPullData(data) { for (var i = data.length - 1; i >= 0; i--) { var li = document.createElement('li'); ul.appendChild(li); li.innerHTML = data[i].value.message; } } /** * 表示しているデータを画面上から削除 */ function removePullData() { for (var i = ul.childNodes.length - 1; i >= 0; i--) { ul.removeChild(ul.childNodes[i]); } }
MilkcocoaのWebサイトでログインして、ダッシュボードから新しいアプリを作成すると、アプリケーションのIDが生成されると思います。アプリケーション名はなんでも良いです。僕は「TutorialApplication」としました。
var milkcocoa = new MilkCocoa('app_id');
main.js
の1行目のapp_idの部分に、そのアプリケーションIDを置き換えてください。
ダッシュボードのアプリケーションの概要から確認することができます。
IDは間違えてGitHubなんかに上げたりしないようにしましょう。
実行
ブラウザを2つ立ち上げてファイルを実行。
ローカル上ですが、ちゃんとリアルタイムでチャットができていることがわかると思います。
デザインを修正して、テキストエリアに文字数制限など設ければ、それなりのものになるのではないでしょうか。
ちなみに、「データを取得」ボタンはこのアプリにおいてまったく必要ないですが、メモとして残しておくことにしています。
BaaSの可能性
このように、短いコードでリアルタイム通信を実現できたわけですが、もっとすごいこともできるらしいです。
MilkcocoaではIoTを見据えてサービスをやっているみたいで、スマホなどのデバイスとの親和性も強いです。公式サイトではRaspberry Piなどを使ったサンプル
も紹介されています。