クジラ型貨物船Docker来航

こんにちイワンコフ。
奥さん、おたくの旦那さん朝の9時ごろに公園のベンチで黄昏てるとこ見ましたよ。

今回は以前にも少し触れたDockerを勉強したいと思います。
今まではXAMPPで開発環境を構築していましたが、時代の波がやっと僕にも押し寄せてきたのでDockerを使って開発環境を構築していこうと思います。

Dockerをインストール

まずはDocker for Windowsのインストールから。
必要条件があるので注意してください。
また、Dockerのアカウントも作成する必要があります。

  • Window10 pro 64bit
  • VirtualBoxなどの仮想化環境をインストールしていない(調べたらVirtualBox6.0からHyper-vと共存が可能らしいです)
  • Hyper-vを有効にしている
  • メモリ4GB以上

満たしてない時はDocker Toolboxというものがあるのでそちらをインストールしてください。

インストールできたらデスクトップにクジラのアイコンができていると思うのでそれを起動しましょう。
そしてPowerShellを開いてちゃんとインストールできるか確認してみます。

PS C:\Users\ユーザー名> docker --version
Docker version 18.09.2, build 6247962

このようになっていればインストールは完了です。

pythonを動かそう

DockerにはまずDockerイメージというものがあってそのDockerイメージをもとにDockerコンテナというものを作成し起動します。
料理で例えるとイメージはレシピ、コンテナは完成した料理といったとこでしょうか。
なんせ流れとしてはイメージを作成してそれをもとにコンテナを作って起動するノリです(笑)

雰囲気を掴むためかるくやってみましょう

PS C:\Users\ユーザー名> docker pull python
Using default tag: latest
latest: Pulling from library/python
5ae19949497e: Pull complete
ed3d96a2798e: Pull complete
f12136850781: Pull complete
1a9ad5d5550b: Pull complete
6f18049a0455: Pull complete
ce39fa9d79d1: Pull complete
3a91ffcf88ea: Pull complete
ee82cc8e1506: Pull complete
bf0dbf90a115: Pull complete
Digest: sha256:87fd2bad3de70a5e779a91d7e2ec2bd01115dfe3faf97dacf730a7f4155d11d8
Status: Downloaded newer image for python:latest

pythonのイメージを作成してみました。
作成といってもDocker Hubという公式イメージ集からプルしてきただけです。(実はこのプル作業ですこしハマってます。最後に解決策をのせときます)

PS C:\Users\ユーザー名> docker image ls
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
python                     latest              42d620af35be        39 hours ago        918MB

無事イメージが作成されていることを確認できました。
次にコンテナの作成と起動をしてpythonを使ってみます。

PS C:\Users\ユーザー名> docker container run -it --name spam python /bin/bash
root@aec5013cf366:/# python --version
Python 3.7.4
root@aec5013cf366:/# python3
Python 3.7.4 (default, Jul 13 2019, 14:04:11)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

おなじみの対話モードです。
雰囲気はこんな感じです。イメージを作ってコンテナを作り起動するイメージはつかめました。(ここでイメージとか言うとややこいぞ)
コマンドの意味は

  • docker container runがコンテナの作成と起動
  • --it-iがコンテナの標準出力を開く、-tが端末デバイスを確保するという意味だそうです。とりあえずおまじないとして覚えておきます。
  • --name spamは作成するコンテナ名
  • pythonはイメージ名
  • \bin\bashはコンテナ内で実行するコマンド

イメージ名を元にspamという名前のコンテナを作り、そのコンテナ内でbashで実行することでLinuxサーバのようにコマンド操作ができる感じ?

PS C:\Users\ユーザー名> docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
d7084f15ef19        python              "python3"           About a minute ago   Exited (0) About a minute ago                       spam

上記のコマンドでコンテナが作成されていることがわかります。

Webサーバを動かそう

次にwebサーバを動かしてみましょう。今回はNginxというサーバを動かしてみたいと思います。
まずはイメージをダウンロードします。

PS C:\Users\ユーザー名> docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
fc7181108d40: Pull complete
d2e987ca2267: Pull complete
0b760b431b11: Pull complete
Digest: sha256:48cbeee0cb0a3b5e885e36222f969e0a2f41819a68e07aeb6631ca7cb356fed1
Status: Downloaded newer image for nginx:latest

docker image lsでイメージが作成されていることを確認した後、サーバを起動します。

PS C:\Users\ユーザー名> docker container run --name webserver -d -p 5000:80 nginx
978a80eda6e32f1ddbb52fcf4a7f4874df8c7573103a666bc38b962e3295cb61
  • --nameはコンテナ名
  • -dはバックグラウンドでの実行
  • -pはポート転送で、ポート番号5000でアクセスしたときコンテナの80番ポートへ転送する仕組みになっています。

localhost:5000でアクセスして下記のような画面が表示されたら成功です。

laravelを動かそう

では実践的にDockerでLaravelの環境を作ってみたいと思います。Laravel学べるゆうてやっていきましょう!
こちらこちらを参考にしています

まず適当なディレクトリを作り、イメージのレシピとなるDockerfileを作ります。
構成は下記のようになります。

FROM php:7.2-fpm

# install composer
RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer
RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim

RUN apt-get update \
    && apt-get install -y libpq-dev \
    && docker-php-ext-install pdo_mysql pdo_pgsql

WORKDIR /var/www/html

いきまり出てきましたDockerfileですが、これがイメージの全貌となります。先ほどはDocker Hubより直接イメージを取得していましたが、今回はイメージファイルを自前で作成しました。拡張子もなしに単にDockerfileという名前でOKです。

これはPHPのイメージなのですがLaravelを使えるように公式のPHPのイメージをベースにカスタマイズしたものです。(Composerを使えるようにしただけです)

その他Webサーバ(Nginx)やDBサーバ(MySql)も用意しますがそれらは公式のイメージからダウンロードしていきます。

公式のイメージはさておき自作したイメージは先ほどのノリでrunしても、そんなイメージはないぜ。ブラザー!と怒られてしまいます。

そこでイメージを作成する必要があるのですが、
docker build -t bro-town ./docker/php/Dockerfileで作成できます。
ここではbro-townが作成されるイメージ名でその後ろがイメージファイルの指定となっています。

次にphp.iniとNginxの設定ファイルを用意します。

[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
server {
  listen 80;
    index index.php index.html;
    root /var/www/html/laravel-manavel-app/public;

  location / {
    root /var/www/html/laravel-manavel-app/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }

あとは作成したPHPとWebサーバとDBサーバのイメージをひとつずつrunしてコンテナを作成したら無事環境構築完了となります。

では、やっていましょう!

普通そんなことやらないぜ。ブラザー

なんかまたブロコップがでてきましたね。
どうゆうことでしょう?
実はDockerにはdocker-composeというコマンドがあり、これは作成したイメージのビルド、公式のイメージのダウンロードやコンテナ名の定義などを一発でやってくれる代物です。
ディレクトリ構成をみると`docker-compose.yml`というymlファイルがありますがこれがdocker-composeするための指示書のようなものです。

version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
    - ./server:/var/www/html

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 5000:80
    volumes:
    - ./server:/var/www/html
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:5.7
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 13306:3306

volumesというオプションがありますが、これは:を基準に左がローカル、右が仮想環境でファイルを共有するという意味です。
これにより./server配下にソースを保存すればそこでの変更が仮想環境にも反映されというわけです。(逆もしかり)

ちなみにDBのvolumesの方ですが、1行目はデータ永続化のためでここでマウントしてないとコンテナを停止したときにDBに保存したデータがなくなってしまいます。
2行目は設定ファイルの共有で、3行はmysqlの公式イメージの機能で./docker/db/sql配下に保存したsqlやシェルスクリプトがコンテナ起動時に実行されると仕組みなっています。ここにDDLなどを保存するのがよさそうですね。

さてここでdocker-compose up -dコマンドを実行します。この時docker-compose.ymlがあるディレクトリに移動して実行しましょう。
するとイメージ作成が始まります。

コンテナ内を確認しましょう。

PS C:\Users\ユーザー名> docker container ls
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                                NAMES
9bf5afcf468f        nginx                 "nginx -g 'daemon of…"   19 seconds ago      Up 15 seconds       0.0.0.0:5000->80/tcp                 nginx
cefccfce2c96        mysql:5.7             "docker-entrypoint.s…"   19 seconds ago      Up 16 seconds       33060/tcp, 0.0.0.0:13306->3306/tcp   db-host
6969d42907ce        laravel-manavel_php   "docker-php-entrypoi…"   5 minutes ago       Up 5 minutes        9000/tcp                             php

php, nginx, db-host 指定した名前のコンテナができています。

次にphpのコンテナ内に入り、Laravelをインストールしていきます。
プロジェクト名は、ここではlaravel-manavel-appとしましたがなんでも構いません。ただしそれに合わしてdefault.confのルートディレクトリも変更してください。

PS C:\Users\ユーザー名\laravel-manevel> docker container exec -it php bash
root@7a36feb581de:/var/www/html# composer create-project --prefer-dist laravel/laravel laravel-manavel-app

ではlocalhost:5000でアクセスしてみましょう

laravelのデフォルト画面が表示されれば成功です。

あとはDB設定を行えば開発環境が整います。

感想

こいつは便利!

おまけ

プルしたとこでハマった内容

PS C:\Users\ユーザー名> docker pull python
Using default tag: latest
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

これはDockerの設定画面の下記のDNS Serverを8.8.8.8に設定してDockerを再起動すると直りました。

その次に、

PS C:\Users\ユーザー名> docker pull python
Using default tag: latest
Error response from daemon: Get https://registry-1.docker.io/v2/library/python/manifests/latest: unauthorized: incorrect username or password

といった内容のエラー。これはDockerにログインすることで解決しました。

PS C:\Users\ユーザー名> docker login
Authenticating with existing credentials...
Stored credentials invalid or expired
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: 登録時のユーザーネーム
Password: 登録時のパスワード
Login Succeeded