20200809のlaravelに関する記事は6件です。

Laravelのpluck()でunicodeが表示される。

問題

formに初期値を入れたくて、LaravelのEloquentで取得した行から
該当するカラムを取得する際に、unicodeでエンコードされた文字列が出力される。

controller.php
$content  = Model::where('id', $id)->first()->pluck('content');

return view('admin.event_chat')
       ->with('content',   $content)
view.blade.php
<form action="/Admin/eventChatSend" method="POST">
      @csrf
      @if (isset($content))
          <input type="text" name="content" value="{{ $content }}">
      @else
          <input type="text" name="content" placeholder="定型文はありません">
      @endif
      <input type="submit" value="送信">
</form>

このように実装した場合、unicodeでエンコードされた文字列contentが挿入されます。

解決案

まぁ、pluck()を通すとunicodeでエンコードされるということは
当たり前のようにpluck()を使わなければいいのでView側で取ってくるか$content = $row->contentで取得すればいいです。前者で実装してみました。

controller.php
$row  = Model::where('id', $id)->first();

return view('admin.event_chat')
       ->with('row',   $row)
view.blade.php
<form action="/Admin/eventChatSend" method="POST">
      @csrf
      @if (isset($row))
          <input type="text" name="content" value="{{ $row->content }}">
      @else
          <input type="text" name="content" placeholder="定型文はありません">
      @endif
      <input type="submit" value="送信">
</form>

$rowがある時は必ず、contentがある程での実装となっています。

まとめ

Laravelでカラムを取得するpluck()を通すとunicodeでエンコードされてしまうので
$row->contentで回避するか、View川で取得すると
utf8でエンコードされた文字列が返ってきます。
どなたかpluck()で文字列をutf8でエンコードする方法をご存知の方はコメントお願いします!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

絶対に失敗しないDockerでLaravel6.8+Vueの実行環境(LEMP環境)を構築する方法〜後編〜

1.バージョン

Laravel 6.8
Vue.js 2.6.11
Docker Desktop 2.3.0.3

2.はじめに

DockerでLaravel+Vue.jsの実行環境を構築する方法をまとめます。

この記事は
絶対に失敗しないDockerでLaravel+Vueの実行環境(LEMP環境)を構築する方法〜前編〜
の後編です。

前編を読んでない方はまず前編を読んでいただければと思います。

前編の続きで以下についてまとめます。

  • Dockerfileを作成する(PHPコンテナのイメージの設計書)
  • Nginxの設定ファイルを作成する
  • イメージの構築(build)
  • コンテナの起動(up)
  • Laravelをインストールする
  • Vue.jsをインストール

3.ディレクトリ構造(完成形)

my-application(*)
├─ docker(*)
│    ├─ php(*)
│    │   └─ Dockerfile
│    └─ web(*)
│        └─ default.conf
│
├─ laravel-vue-app(*)
│    └─ ここにLaravelのPJディレクトリが作られる
│    
└─ docker-compose.yml

(*)のディレクトリ名は任意です。

4.Dockerfileを作成する(PHPコンテナのイメージの設計書)

PHPコンテナにはLaravelをインストールするためのパッケージ管理ツールであるComposerVue.jsをインストールするためのパッケージ管理ツールであるnpmをそれぞれインストールする必要があります。

※フロントエンドにVue.jsを使わない場合は該当箇所は追記せずに進めてもらってOKです。
※例えばフロントエンドはJavaScript、jQueryのみの場合

そのため、カスタマイズしたイメージを使うのでイメージの設計書であるDockerfileを作成します。

4-1.Dockerfileの完成形

以下のphpディレクトリ(名前は任意)配下にDockerfileを作成してください。(拡張子不要)

my-application(*)
├─ docker(*)
│    ├─ php(*)
│    │   └─ Dockerfile←ココ

完成形のDockerfileが以下です↓

Dockerfile
#イメージのベースを指定
FROM php:7.2-fpm

#パッケージ管理ツールapt-getの更新と必要パッケージのインストール
RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim \
libpq-dev

#composerをインストール
RUN cd /usr/bin \
&& curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer 

#npmインストール
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
&& apt-get install -y nodejs

#MySQLを使えるようにする
RUN docker-php-ext-install pdo_mysql pdo_pgsql 

#コンテナ内に入った時のディレクトリを指定
WORKDIR /var/www/html

Dockerfileの内容の詳しい説明は割愛します(というか自信がないw)が、ざっくり説明します。

4-2.イメージのベースを指定

FROM php:7.2-fpm

今回構築するPHPコンテナはphp:7.2-fpmのイメージをベースに作成します。
(PHP7系です)

4-3.パッケージ管理ツールapt-getの更新と必要パッケージのインストール

RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim \
libpq-dev

Docker for Macの場合はapt-getというパッケージ管理ツールを使って必要なパッケージ・ライブラリをインストールします。
その前に一度apt-getを最新にするために

RUN apt-get update

を実行してます。(RUNでイメージ構築時にLaravelコマンドを実行します)

4-4.composerをインストール

RUN cd /usr/bin \
&& curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer

LaravelComposerというパッケージ管理ツールでインストールするのでComposerをインストールします。

Composer公式HP

4-5.npmインストール

#npmインストール
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
&& apt-get install -y nodejs

Vue.jsはnode.jsのパッケージ管理ツールであるnpmを使ってインストールするのでnpmをインストールします。

※フロントエンドにVue.jsを使わない方はこちらは飛ばしてOKです。

なお、npmVue.jsのインストールにはこちらの記事を参考にしましたので合わせて読んでいただければと思います。

お手軽laravel Vue.js docker-compose環境構築

4-6.MySQLを使えるようにする

RUN docker-php-ext-install pdo_mysql pdo_pgsql 

docker-php-ext-installでPHPの拡張モジュールをインストールすることができます。

4-7.コンテナ内に入った時のディレクトリを指定

WORKDIR /var/www/html

WORKDIRはWork Directoryの略で、PHPコンテナ(app)に入った時のカレントディレクトリになります。
つまり、docker-compose exec app bashでappコンテナの中に入った場合、/var/www/htmlがカレントディレクトリになります。

Laravelで使うコマンドである$ php artisan 〜を使うためには、後に作るlaravel-vue-appディレクトリに移動する必要があるので、/var/www/htmml/var/www/html/laravel-vue-appに変更しても問題ありません。
(むしろそっちの方が後々楽かも...)

4.Nginxの設定ファイルを作成する

次にNginxの設定ファイルdefault.confを、webディレクトリ配下に作成します。

my-application(*)
├─ docker(*)
│    ├─ php(*)
│    │   └─ Dockerfile
│    └─ web(*)
│        └─ default.conf←ココ

全体のコードはこちらです↓

default.conf
server {
    listen 80;

    root /var/www/html/laravel-vue-app/public;
    index index.php index.html index.htm;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

この設定ファイルで注意するところは2箇所です。
まず1つ目はこちら↓

    listen 80;

docker-compose.ymlで設定したportsオプションのコンテナ側のポート番号と一致させてください。

  web:
    image: nginx:1.15.6
    ports:
      - '8000:80'←ココ

2つ目は

    root /var/www/html/laravel-vue-app/public;
    index index.php index.html index.htm;

ここはLaravelのプロジェクトファイルを作成するディレクトリを使います。

my-application(*)
├─ docker(*)
│    ├─ php(*)
│    │   └─ Dockerfile
│    └─ web(*)
│        └─ default.conf
│
├─ laravel-vue-app(*)←ココ
│    └─ ここにLaravelのPJディレクトリが作られる

今回はlaravel-vue-appというディレクトリにしているので

/var/www/html/larave-vue-app/public;

ですね。

laravel-vue-appディレクトリはLaravelのインストール時に自動的に作られるので今作っておく必要はありません)

/var/www/htmldocker-compose.ymlのappコンテナでもローカルと対応づけしてましたよね。

  app:
    build: ./docker/php
    volumes:
      - .:/var/www/html←ココ

ローカルの./laravel-vue-appつまりmy-application/laravel-vue-app/var/www/html/laravel-vue-appと対応付けされます。(これをマウントするとも言います)

ちなみにpublicはLaravelのプロジェクトを作成すると自動的に作られます。

2行目のこちら↓ですが、「Nginxにアクセスした時に初めに/public/index.phpが処理されます」という設定です。

index index.php index.html index.htm;

index.phpがなければindex.htmlが、それもなければindex.htmが処理されますが、index.phpがないことはないのでindex.phpだけでもいいかもしれませんが念のために書いておきます。

Laravelプロジェクトでpublic/index.phpがどのような処理をしているかはこちらの記事に詳しく書いてますが、環境構築するに当たってはあまり必要ないかなと思います。

public/index.phpからミドルウェア/コントローラーが実行されるまで - Laravelコードリーディング

これで環境構築に必要な各種設定ファイルの作成は終了です!
(長かったですね...お疲れ様です)

5.イメージの構築(build)

それではまずはDockerfileからイメージを構築します。

ターミナルでmy-applicationディレクトリに移動します。

$ cd my-application

配下のディレクトリ・ファイルを確認します。

$ ls

ここで以下の表示が出ればOKです。

docker    docker-compose.yml

docker-composeコマンドは`docker-compose.ymlがあるディレクトリでなければ実行できません。

それでは以下のコマンドでイメージを構築(build)します。

$ docker-compose build

時間がかかると思いますが、以下の表示が出ればbuild成功です。

Successfully built 27d58ffbe8e1
Successfully tagged my-application_app:latest

これでPHPコンテナ用のイメージが完成です。
(他のコンテナは既存のイメージをそのまま使うのでbuild不要)

※builtの後の数字がランダムなので人それぞれ変わります。

6.コンテナの起動(up)

それではイメージを元にコンテナを起動します。

docker-compose buildを実行したディレクトリで以下のコマンドを実行します。

$ docker-compose up -d

実行後、以下の表示が出ればコンテナの起動は完了です。

Creating network "my-application_default" with the default driver
Creating volume "my-application_mysql-volume" with default driver
Creating my-application_app_1 ... done
Creating my-application_db_1  ... done
Creating my-application_web_1 ... done

これで各種コンテナの起動完了です。

7.Laravelのインストール

構築したDocker環境にLaravelをインストールします。
以下の手順で進めます。

  • Composerのバージョン確認
  • Laravelの新規プロジェクト作成

7-1.Composerのバージョン確認

まずはComposerがインストールできているか確認します。
(これはLaravelのインストールに必要というよりLaravelの新規プロジェクトを作成できる状態なのか、の確認です)

先ほどまでと同じディレクトリで以下のコマンドを実行し、appコンテナの中に入ります。

$ docker-compose exec app bash

実行すると以下のように/var/www/htmlディレクトリに変わります。(これは既にコンテナ内部にいます)

root@d1138847703d:/var/www/html#

以下のコマンドでComposerのバージョンを確認します。

$ composer --version

バージョンが表示されればOKです。

7-2.Laravelの新規プロジェクトを作成

ディレクトリは変えずに以下のコマンドを実行します。

composer create-project --prefer-dist "laravel/laravel=6.8.*" laravel-vue-app

これでLaravel6.8を指定してlaravel-vue-appという新規プロジェクトが作成されます。

laravel-vue-appというディレクトリも一緒にmy-applicationディレクトリに配下に作成され、コンテナ内の/var/www/htmlディレクトリ配下にマウントされます。

Laravelの5系を使いたい方は6.8のところを適宜変えてください。
(ただし、動作確認はこちらではしていませんのでご了承ください)

時間がかかりますが、以下のコマンドが表示されればOKです。

Package manifest generated successfully.

その後に以下のコマンドが表示されていても問題ありません。

39 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan key:generate --ansi
Application key set successfully.

ローカルのmy-application配下及びコンテナの/var/www/html配下にlaravel-vue-appディレクトリとlaravelプロジェクトのディレクトリがたくさんできています。

スクリーンショット 2020-08-09 16.44.37.png

7-3.LaravelとMySQLとの接続を設定する

Laravleでの開発が行えるようにMySQLとの接続を設定します。

エディターでlaravel-vue-appを開いて.envを開きます。

9〜14行目からを以下のように修正します↓

.env
DB_CONNECTION=mysql
DB_HOST=db(←コンテナ名)
DB_PORT=3306(←コンテナ側のポート番号)
DB_DATABASE=db_name
DB_USERNAME=db_user
DB_PASSWORD=db_password

これはdocker-compose.ymldbコンテナの設定と合わせます。

  db:
    image: mysql:5.7
    ports:
      - '3306:3306'
    environment:
      MYSQL_DATABASE: db_name
      MYSQL_USER: db_user
      MYSQL_PASSWORD: db_password

.envの5行目も以下の通り修正します。

APP_URL=http://localhost:8000

次にコンテナ内でlarave-vue-appディレクトリに移動します。

$ cd laravel-vue-app

そこで以下のコマンドを実行します

$ php artisan migrate

以下のコマンドが表示されればOKです。

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.07 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.04 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.02 seconds)

では、一度コンテナから出て、再度コンテナの停止(破壊も行われる)・起動を実行します。

$ exit
$ docker-compose down
$ docker-compose up -d

ブラウザでlocalhost:8000にアクセスするとLaravelのページが表示されます。

これで Dockerを使ったlaravelの実行環境(LEMP環境)の構築は完了です!

スクリーンショット 2020-08-09 17.12.30.png

8.Vue.jsのインストール

次にVue.jsを使えるようにします。

laravel-vue-app配下のpackage.jsonの19行目から以下の通り編集します。

package.json
        "sass-loader": "^7.1.0",(←カンマ追記)
        "vue": "^2.6.11",(←追記)
        "vue-template-compiler": "^2.6.11"(←追記)

追記したらappコンテナに入り、laravel-vue-appに移動します。

$ docker-compose exec app bash
$ cd laravel-vue-app

以下のコマンドを実行します。

$ npm install

これでVue.jsのインストールも完了です。

9.まとめ

これでDockerでLaravel6.8+Vueの実行環境(LEMP環境)の構築ができました。

間違っていることや不明点があればお気軽にコメントいただければと思います。

前編はこちら↓
絶対に失敗しないDockerでLaravel6.8+Vueの実行環境(LEMP環境)を構築する方法〜前編〜

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

絶対に失敗しないDockerでLaravel+Vueの実行環境(LEMP環境)を構築する方法〜前編〜

1.バージョン

Laravel 6.8
Vue.js 2.6.11
Docker Desktop 2.3.0.3

2.はじめに

DockerでLaravel+Vue.jsの実行環境を構築する方法をまとめます。

ネットにはDockerdでLaravel実行環境を構築する方法はありますが、多くの記事が設定コードを載せているだけで詳しい説明がなかったので、「この記事だけ読めばある程度意味を理解でき、絶対に環境構築が成功する」という記事を執筆しようと思いました。

構築する環境はLEMP環境で構成は以下の通りです。

ミドルウェアの種類 頭文字 ミドルウェア名 備考
OS L Linux (※)
Webサーバー E Nginx エンジンエックスと読む
データベース M MySQL 特になし
アプリケーション P PHP フレームワークはLaravelを使う

NginxMySQLPHPの3つをコンテナの設定を行います。

(※)僕がググる中で「あれ、Linuxのコンテナは要らないの?」と疑問に思ってたのですが、Docker for Macを使うとMacOSに標準装備されているHyperKitという仮想化ツールによってLinuxの仮想マシンが自動で起動してくれるので後述するコンテナの設定ファイルにはOSに関する記述は不要です。(詳しくは下の記事)

Docker for Macでおこなっていることのまとめ(メモ)

3.注意点

  • この記事を見ながら環境構築する場合はMacOSをオススメします。
  • この記事で使うDocker imageのバージョン(tag No.)以外のバージョンでの動作確認はしておりません。
  • DockerやDocker-Composeの概要に関する説明ほとんどしませんのでDockerに対する理解が浅い方は以下の記事などを参考に勉強しておくことをオススメします。

【図解】Dockerの全体像を理解する -前編-

4.全体の手順

  • DockerとDocker Composeを使えるようにする
  • docker-compose.yml(コンテナの設定ファイル)を作成する
  • Dockerfileを作成する(PHPコンテナのイメージの設計書)
  • Nginxの設定ファイルを作成する
  • イメージの構築(buid)
  • コンテナの起動(up)
  • Laravelをインストールする
  • Vue.jsをインストール

5.DockerとDocker Composeを使えるようにする

まずはDockerDocker-Composeをお使いのPCで使えるようにします。

Dockerを使えるようにするためにVagrantでLinux系のOSの仮想マシンを構築→仮想マシンにDockerをインストール→Dockerを使えるようにする方法(Docker on Vagrant)でも良いですが、DockerDocker Composeのインストールが簡単にできるDocker Desktop(Docker for Mac)を使います。
(僕は実務でもDocker Desktopを使っています)

Docker Desktopのインストール方法はググればたくさん出てくるのでここでは説明しませんが、下の記事を見れば問題なくインストールできると思います。

DockerをMacにインストールする(更新: 2019/7/13)

インストールが終わったらターミナルで以下のコマンドを実行してバージョン情報が表示されればインストールは正常にできています

Dockerのバージョン確認↓

$ docker -v

Docker-Composeのバージョン確認↓

$ docker-compose -v

6.ディレクトリ構造

6-1.完成形のディレクトリ構造

my-application(*)
├─ docker(*)
│    ├─ php(*)
│    │   └─ Dockerfile
│    └─ web(*)
│        └─ default.conf
│
├─ laravel-vue-app(*)
│    └─ ここにLaravelのPJディレクトが作られる
│    
└─ docker-compose.yml

(*)のディレクトリ名は任意でOKです。
(default.confも好きなファイル名でよかったかも...です)

なお、ディレクトリ構造はこれでなければできないなんてことは全くありません。
僕が環境構築したディレクトリ構造をそのまま載せてますのでお好みで編集していただいて構いません。

※ディレクトリ構造を変更すると、後ほど作成するdocker-compose.ymlの設定内容を適宜修正する必要がありますのでちょっと自身がないな、という方はそのままマネして作ってもらえたらOKです。

6-1.必要なディレクトリを作成する

まず、好きな場所(デスクトップでもユーザーディレクトリでもOK)にmy-application(名前は自由)ディレクトリを作成します。

その下にdockerディレクトリを作成します。
次にdockerディレクトリの中に以下2つのディレクトリを作成します。

  • php(名前は自由)
  • web(名前は自由)

すると、以下のディレクトリ構造になると思います。

my-application(*)
└─docker(*)
     ├─ php(*)
     └─ web(*)

これで準備はOKです。

これからの各作業によって完成形のディレクトリ構造にします。

  • phpの中にはPHPコンテナ用のDockerfileを作成する
  • webの中にNginxの設定ファイル(default.conf)を作成する
  • laravel-vue-appディレクトリはLaravelインストール時に自動的に作られる
  • docker-compose.ymlは次のセクションで作成する

7.docker-compose.yml(コンテナの設定ファイル)を作成する

ではここから各種コンテナの設定をしていきます。
ミドルウェア毎に複数のコンテナを作成・管理する場合はコンテナの設定ファイルであるdocker-compose.ymlを作成します。

my-applicationディレクトリ配下に作成してください。

7-1.全体のコード(完成形)

まずは全体のコードはこちらです。

docker-compose.yml
#docker-compose.ymlのバージョン
version: '3'
#docker volumeの設定
volumes:
  mysql-volume:

#services以下に各コンテナの設定を書く
services:
  #Webサーバーのコンテナ
  web:
    image: nginx:1.15.6
    ports:
      - '8000:80'
    depends_on:
      - app
    volumes:
      - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf
      - .:/var/www/html
  #アプリケーションのコンテナ
  app:
    build: ./docker/php
    volumes:
      - .:/var/www/html
  #データベースのコンテナ
  db:
    image: mysql:5.7
    ports:
      - '3306:3306'
    environment:
      MYSQL_DATABASE: db_name
      MYSQL_USER: db_user
      MYSQL_PASSWORD: db_password
      MYSQL_ROOT_PASSWORD: root
      TZ: 'Asia/Tokyo'
    volumes:
      - mysql-volume:/var/lib/mysql

7-2.docker-compopse.ymlのバージョン

まずはこちらのコードです。

version: '3'

今docker-compose.ymlファイルを作成する場合はversion: '3'と書いておけば間違いないです。

このバージョンはdocker-compose.yml(Composeファイル)のバージョンでありDocker Composeのバージョンとは違います。
公式サイトにも一応書いてます)

まあ、お決まり事みたいなことなのでそんなに深く考えなくていいかなと思います。

7-3.Webサーバー(Nginx)コンテナの設定について

WebサーバーにはNginxを使います。

Nginxコンテナの設定はこちら↓

  web:
    image: nginx:1.15.6
    ports:
      - '8000:80'
    depends_on:
      - app
    volumes:
      - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf
      - .:/var/www/html

7-3-1.コンテナ名

  web:

はコンテナ名を表します。
今回はwebというコンテナ名にしました。
こちらも決まりはないので好きに命名してOKですが、webweb_serverがわかりやすくて無難かなと思います。

7-3-2.イメージ

imageオプションはコンテナの元になるイメージを設定します。このimgae:の右に書いたイメージをDokcerHub(Docker imageを共有するプラットフォーム)から持ってきます(pullすると言う)。

    image: nginx:1.15.6

NginxコンテナはDockerHubからnginx 1.15.6のpullしてそれを元に起動します。

nginx:1.15.6(DockerHub公式サイト)

7-3-3.ports

portsはローカルとDockerコンテナ間のポート番号の対応付けを設定するオプションです。

    ports:
      - '8000:80'

ローカルのポート番号8000とコンテナ内のNginxのポート番号80(Nginxのデフォルトのポート番号)をリンクさせています。

これでNginxコンテナが起動している状態でローカルのlocalhost:8000にアクセスするとNginxの80番ポートにアクセスすることができます。

7-3-4.depends_on

depends_onはコンテナ間の依存関係を設定するオプションです。

    depends_on:
      - app

appはPHP(アプリケーション)コンテナです。
NginxはPHPを実行するため、PHP→Nginxの順にコンテナを起動するようにdepends_onでコンテナ同士の関係を設定しています。

    depends_on:
      - 先に起動するコンテナ名

初めて環境構築する方でちょっと内容が難しいと感じる方はここはあまり深く考えずに進んでもOKです。

7-3-5.volumes

volumesはローカルとDockerコンテナ間のファイル共有を設定するオプションです。

    volumes:
      - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf
      - .:/var/www/html

ここでは./docker/web/default.conf/etc/nginx/conf.d/default.confをリンク(対応)付け、
./var/www/htmlをリンク(対応)付けしてます。(.はカレントディレクトリです)

volumesオプションはローカルのディレクトリとDockerコンテナ内のディレクトリを:で対応させます。

volumesでディレクトリをリンクさせることにより、Dockerコンテナ内で/var/www/html/に移動した時にローカルの.以下のディレクトリ、ファイルがそこにあるように(実際にはない)共有することができます。
(ちょっとここ言葉で上手く説明するのが難しいのでわかりにくかったらすみません...)

また、ローカルで.以下のファイルを修正するとDockerコンテナ内にもその修正が反映されます。

書き方は以下の通りです↓

    volumes:
      - (ローカル):(Dockerコンテナ内)

ここはDocker環境を構築する上でもしっかり理解しておくべき内容だと思います。

7-4.アプリケーション(PHP)コンテナの設定について

アプリケーションはLaravelを使うのでもちろんPHPにします。
PHPコンテナの設定はこちら↓

  app:
    build: ./docker/php
    volumes:
      - .:/var/www/html

7-4-1.コンテナ名

コンテナ名はappにしてます。ここも任意ですが、他にはphpphp_serverが無難かと。

7-4-2.build

buildはDockerHubのイメージをそのまま引用するのではなく、DockerHubのイメージをベースにオリジナルのイメージを作成する(buildする)ときに用います。

    build: ./docker/php

これで./docker/phpの配下にあるDockerfileというテキストファイルの内容にのっとってイメージを構築していくという設定をしています。

ディレクトリ構造の抜粋↓

my-application(*)
├─ docker(*)
│    ├─ php(*)
│    │   └─ Dockerfile

docker-compose.ymlから見て./docker/phpの配下にちゃんとDockerfileがありますね。
Dockerfileの内容については後ほど解説します。

7-4-3.volumes

    volumes:
      - .:/var/www/html

ローカルの.とDockerコンテナ内の/var/www/htmlをリンクさせています。
Webサーバーの時も/var/www/htmlが出ましたがこれは覚えておいて良いと思います。
(以下の記事を読んでみても良いかも)

7-5.データベース(MySQL)コンテナの設定について

DBはMySQLを使います。
MySQLコンテナの設定はこちら↓

  db:
    image: mysql:5.7
    ports:
      - '3306:3306'
    environment:
      MYSQL_DATABASE: db_name
      MYSQL_USER: db_user
      MYSQL_PASSWORD: db_password
      MYSQL_ROOT_PASSWORD: root
      TZ: 'Asia/Tokyo'
    volumes:
      - mysql-data:/var/lib/mysql

7-5-1.コンテナ名

コンテナ名はdbにしてます。ここも任意ですが、他にはmysqldb_serverが無難かと。

7-5-2.イメージ

    image: mysql:5.7

MySQLコンテナもNginxコンテナ同様、DockerHubからイメージをpullして使います。
今回はmysql:5.7のイメージを使用します。

7-5-3.ports

    ports:
      - '3306:3306'

Nginxコンテナの設定方法と同様で、ローカルの3306番ポートとDockerコンテナの3306番ポートを共有しています。(3306はMySQLのデフォルトのポート番号)

注意点として、他のアプリケーションでローカルのMySQLに3306番ポートで接続している場合、同じポート番号は使用することができないので:より左側の3306を適当な番号にしてください。(僕はカブっていたので変えました)

MySQLコンテナのポート番号(:より右側)は3306で問題ありません。

7-5-4.environment 

environmentは文字通りですが、MySQLの環境変数を設定するオプションです。

    environment:
      MYSQL_DATABASE: db_name
      MYSQL_USER: db_user
      MYSQL_PASSWORD: db_password
      MYSQL_ROOT_PASSWORD: root
      TZ: 'Asia/Tokyo'
  • MYSQL_DATABASE:DBの名前(好きな名前でOK)
  • MYSQL_USER:MySQLのユーザー名(好きな名前でOK)
  • MYSQL_PASSWORD:MySQLのパスワード(好きな名前でOK)
  • MYSQL_ROOT_PASSWORD:ルート権限のパスワード(rootが一般的かなと思います)
  • TZ:時間設定(Time Zone)

※ひょっとするとLaravel側でタイムゾーンを設定するのでここには不要かもしれませんが一応つけておきました。

あと、構築したファイルをGitHubに上げる場合はここの環境変数は変えてください。

7-5-5.volumes

volumesは先ほどまでと同じ考え方です。
が、データベースの場合はDocker VolumeというDockerのオプションを使用します。

    volumes:
      - mysql-data:/var/lib/mysql

Docker Volumeとはデータを永続的に保存できるようにする仕組みのことで、保存場所のことをvolume(ボリューム)と呼びます。

「なぜデータベースの時にボリューム(という場所)を使うのか」というと、コンテナは停止する時に起動していた物を壊すのでデータベースに保存しているデータがコンテナの停止とする度に消えてしまうからです。

なので開発するWebアプリケーションで扱うデータの保存先であるボリュームを用意する必要があるわけです。
(もちろんですが、ボリュームはコンテナの外に作られます)

コンテナの動作は簡単にいうと「起動→停止→破壊」です。で、起動し直す時は新たにコンテナを作って立ち上げます。

上の設定コードからローカルのmysql-volumeというボリュームとMySQLコンテナの/var/lib/mysqlをリンクさせています。

Docker Volumeの定義はdocker-compose.ymlの上部にあります。

volumes:
  mysql-volume:

Docker Volumeはこちらの記事がわかりやすいです↓

Docker、ボリューム(Volume)について真面目に調べた

これで3つ全てのコンテナの設定が終了です。

8.ここまでの全体像

ここまでの内容をざっくりまとめると以下の通りです。

  • Dockerを用いたLEMP環境構築ではNginxMySQLPHPのコンテナを準備する
  • versionは3でOK
  • DockerHubのイメージを引用(流用)する場合はimage、Dockerfileからイメージを構築(build)する場合はbuildオプション
  • portsはローカルとコンテナ内のポート番号を対応づけるオプション
  • depends_onはコンテナ間の依存関係を設定するオプション
  • volumesはファイル共有を設定するオプション
  • environmentは環境変数を設定するオプション
  • Docker Volumeはデータベースのコンテナを設定する時に用いる仕組みでデータを永続的に保存することができるボリューム(というデータ保存場所)をコンテナの外に作る

後編へ続く

環境構築を1つの記事にまとめようと思ったのですが、まだまだ執筆ボリュームもありかなり長くなるので後編で残りの以下をまとめようと思います。

  • Dockerfileを作成する(PHPコンテナのイメージの設計書)
  • Nginxの設定ファイルを作成する
  • イメージを構築(buid)する コンテナを起動(up)する
  • Laravelをインストールする
  • Vue.jsをインストール

ここまでで間違っていることや不明点があればお気軽にコメントいただければと思います。

後編はこちら
絶対に失敗しないDockerでLaravel6.8+Vueの実行環境(LEMP環境)を構築する方法〜後編〜

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テクトロジーによる実践的組織構造学

今回の記事では、ソ連の革命家、医師、哲学者、小説作家であったアレクサンダーボグダノフが提唱したテクトロジーと呼ばれる実践的組織構造学について紹介する。
テクトロジーでは組織が安定、成長、破綻する環境、条件について詳細に解説し、安定した組織を生成する手法について解説している。
テクトロジーの概念を拝借し、創造的な組織創造の手法を紹介したいと思う。

テクトロジーにおける組織の定義

テクトロジーでは、組織をオープンクローズ型の成長する有機体システムと定義している。
組織とは以下の要素で構成されている。
ビジョン・・・組織の目指すべき方向性。
経済・・・組織のボディ。巨大であるほど収容できる人の人数が増加する
金融・・・組織を循環する血液。
生産・・・もの、サービスを生産し、組織の経済を巨大化する手段。

これらの有機的な要素が相互作用し、成長することで組織という有機体が構成されていると考える。

テクトロジーにおける成長する有機体システムとは

テクトロジーでは、組織をオープンクローズ型の成長する有機体システムと定義している。
テクトロジーにおける組織の定義を中国の陰陽論によって説明することができる。
陰陽論とは、原初は混沌(カオス)の状態であると考え、この混沌の中から光に満ちた明るい澄んだ気、すなわち陽の気が上昇して天となり、重く濁った暗黒の気、すなわち陰の気が下降して地となった。この二気の働きによって万物の事象を理解し、また将来までも予測しようというのが陰陽思想である。
組織が外部からエネルギーを取り入れ、出力するインプット、アウトプットの運動を陰陽論における陽の気と捉えることができる。
逆に組織内部に沈殿し、成長し、ヒエラルキーを形成する秩序生成を担う運動を陰陽論における陰の気と捉えることができる。

テクトロジーにおける生産の定義

テクトロジーでは、組織における生産活動は以下の3つに分類されている。
人の生産・・・人に教育を施し、組織活動に従事する生産者を作成する
モノ、サービスの生産・・・外部から取得した資材を用いて、モノ、サービスの生産を行う。
アイデア・・モノ、サービスを生成するための知識、アイディアを作成する。
組織における生産活動を高めることで、組織の経済を成長させることができる。

テクトロジーにおける組織が不安定化する条件

テクトロジーにおける組織が不安定化する条件として以下の2点が挙げられる。
・外部からのエネルギー取得の減少・・外部から人、モノ、金の循環が減少することで組織のサイズ、経済を維持することできなくなる。
・ヒエラルキーシステムの固定化・・・ヒエラルキーシステムが巨大化し、組織が硬直化してしまう。
組織不安定化を回避する手法として以下の手段が有効とされている。
生産手段を研究、開発、更新を行い、組織の経済成長のスピードを増加させる。
組織が硬直化の原因になっているヒエラルキーシステムを解体し、適切なサイズに組み替える。

まとめ

アレクサンダーボグダノフテクトロジーに関するアイディアを発表した時期は1920年代である。
独学で組織が破綻する条件、環境を発見し、持続可能な成長のコンセプトを提唱したアレクサンダーボグダノフの先見性は恐るべきものである。
ソ連は軍事、IT、経済においてアメリカと張り合うことができた超大国だった。
ソ連時代に考えられたアイディア、思想などは現代においても見直されるべきものだと思われる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel-cors v2 の HandleCors ミドルウェアは CSRF 対策用途には使えない

はじめに

Web サービスの開発で Laravel × Vue.js という構成を聞くことが多くなってきたのではないでしょうか?
この記事は、私が個人サービスを開発している際にハマった、あるライブラリについてのお話です。

この記事を書くにあたり、私の師匠(自称)であるまっぴー(@mpyw)さんに助言を頂きました。
ありがとうございます!!!!!!

また、ここでは CSRF 対策や同一オリジンポリシーの基礎知識について詳しく掘り下げません。
私の師匠がとても良い記事を書かれているので、そちらを読んでいただき :sparkles: CSRF 対策と同一オリジンポリシーを完全に理解 :sparkles: した上でこの記事を読むとわかりやすいと思います。

これで完璧!今さら振り返る CSRF 対策と同一オリジンポリシーの基礎

laravel-cors って?

ご紹介しましょう、これこそが私がドハマりしたライブラリです。
Laravel において CORS(Cross-Origin Resource Sharing) の導入を行う際に非常に便利なもので、許可するオリジンの設定に正規表現を用いることができたり、様々な拡張に対応しています。
Laravel7 からデフォルトでインストールされるようになっています。

ちょっと整理してみよう

Web サービスを Laravel × Vue.js という構成で開発する場合、大抵以下のふたつの方法があります。

  • Laravel 自体に Vue.js のコンポネートを流し込む
  • 別々のアプリケーションとして開発を行う

Laravel 自体に Vue.js のコンポネートを流し込む場合は、Laravel に標準で用意されているresource/js/bootstrap.js を用いることでLaravel 単体で開発を行うときと同じように、CSRF トークンを使って CSRF 対策を行うことができます。

別々のアプリケーションとして開発を行う場合も、フロントエンドがバックエンドから送られてくる XSRF-TOKEN を用いて CSRF 対策を行うことは可能ですが、XSRF-TOKEN は Cookie でサーバ側から配信されるためステートフルなWebサービスの場合にしか使えません。

また、別々のアプリケーションとして開発を行う場合では

  • example.com (フロントエンド)
  • api.example.com (バックエンド)

のようにドメインを分けて運用されることが多々あります。
このような構成で、フロントエンドがバックエンドに対してリソースを要求すると、セキュリティ上の理由によりブラウザ自身が 同一オリジンポリシー に従ってリクエストの結果の読み取りをブロックします。
つまり、リクエストは送れてもレスポンスは読み取れないよってことです。

同一オリジンポリシーに対して、このドメインに対するリソースの要求は安全なものであることを示し、レスポンスを読み取れるようにするのが CORS (Cross-Origin Resource Sharing) にある Access-Control-Allow-Origin などです。

では、ステートレスなアプリケーションの場合やドメインがフロントエンドとバックエンドで別れている場合はどのような CSRF 対策を施したらよいのでしょうか?

Origin をサーバーサイドで検証しよう

師匠の記事をよく読み、理解されている方はお察しだと思いますが、上記のような場合はサーバーサイド側で Origin ヘッダを検証することで CSRF 対策を行うことができます。

これは、現在閲覧しているサイトのURLを示す Origin ヘッダが特殊な方法を用いなければ偽装することができず、意図しているオリジンからのリクエストであることをサーバーサイド側で検証することができるからです。

本題

私がハマったのは、ズバリ laravel-cors v1.x では Origin ヘッダをしっかりとライブラリで検証していたが、laravel-cors v2.x では Origin ヘッダを検証するのをやめていた という点です。

以下の画像を御覧ください
これは、laravel-cors のベースとなっているライブラリ stack-cors を Origin ヘッダの検証を削除したもの(v2.x)へバージョンアップするためのPRです。

スクリーンショット 2020-08-09 13.21.51.png
https://github.com/fruitcake/laravel-cors/pull/443

ここには、「厳密なオリジンの検証はブラウザ側に任せ、キャッシュ性を向上させる」とあります。

? CORS ≠ CSRF 対策 ?

よく、CORS を導入しているから CSRF 対策ができているという話を聞きますが、これは間違いです。
CORS はあくまで、サーバーに対して別ドメインからリソースを要求し、その結果の読み取りをブロックするものであり、サーバーへのリクエストを制限するものではないからです。

よく考えればそれはそう

上記で説明したように、CORS はあくまで返ってきた結果が不正なコードに参照されることを防ぐためのもので、CSRF 対策にはなんら関係がありません
ライブラリとして持つ責任の範囲を明確にして、厳密なオリジンの検証が必要であればユーザーの実装に任せるというもので、とてもよい変更だったと思います。

解決策

laravel-cors v2.x で CSRF 対策ができないことはわかりました。
では、自分でやるしかないでしょう!!!!!
CSRF 対策を自分でするにあたって、要件を書き出しでみましょう。

  • メインリクエストでオリジンを検証すること
  • リクエストに Origin ヘッダが含まれていない場合は通す

リクエストに Origin ヘッダが含まれていない場合に通すのは、同一オリジンの場合 Origin ヘッダーを付与しない という挙動をするブラウザがあるためです。

これを踏まえて、ミドルウェアを書いてみましょう!
ここでは師匠が書いてくださっていたコードを引用させていただきます。

VerifyOrigin.php
<?php

namespace App\Http\Middleware;

use Asm89\Stack\CorsService;
use Closure;
use Symfony\Component\Finder\Exception\AccessDeniedException;

class VerifyOrigin
{
    protected CorsService $cors;

    public function __construct(CorsService $cors)
    {
        $this->cors = $cors;
    }

    public function handle($request, Closure $next)
    {
        // Origin ヘッダがリクエストに含まれていて、かつそのオリジンが許可対象である
        if ($request->hasHeader('Origin') && !$this->cors->isOriginAllowed($request)) {
            throw new AccessDeniedException('The request from your origin is not allowed.');
        }

        return $next($request);
    }
}

このミドルウェアを使うことで、CSRF 対策もしっかりと行うことができます!

おわりに

おわりに、といってもあんまり書くことないんですが…w
今回の記事は、自分の復習のために書いてみました。
CORS や CSRF 対策に関して再確認ができてよかったです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel で Access-Control-Allow-Origin ヘッダーを付与しても CORS エラーが解消しない

よくよく考えれば当たり前のことだったんですが、若干ハマってしまったので・・・
同様にハマった人の助けになれば幸いです。

普通に CORS 対応をすすめる

Access-Control-Allow-Origin などをレスポンスヘッダーに含ませる Middleware の作成

いろいろな人が記事をまとめてくれているので、ググればすぐ見つかると思います。

各ヘッダーの意味はこちらを参照。
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers

App\Http\Middleware\Cors
<?php

namespace App\Http\Middleware;

use Closure;

class Cors
{
    public function handle($request, Closure $next)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Access-Control-Allow-Methods', 'GET, POST')
            ->header('Access-Control-Allow-Headers', 'Accept, X-Requested-With, Origin, Content-Type');
    }
}

api Middleware グループに追加します。
これで api 全体に適用されるようになります。(もちろんルーティング定義の際に api Middleware グループを指定している場合に限ります)

App\Http\Kernel
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{

    :

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        'api' => [
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\Cors::class, // ★追加
        ],
    ];

    :

}

大抵はこれで十分なんですが、 プリフライトリクエストが発生する場面ではこれだけでは不十分でした。
プリフライトリクエストについてはこちら
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#Simple_requests
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#Preflighted_requests

プリフライトリクエストの場合は api Middleware が使用されない

どうやらプリフライトリクエストについてのルーティング定義は自動的に Laravel が作成するようです。
その場合は、Middleware の適用などが行われません。

つまり

こんなルーティング定義を用意しておきます。

Route::get('sample', function () { echo 'sample api'; });

URL や Middleware の適用はこんな状態です。
http://domain/api/sample にアクセスすると api Middleware グループが適用されます。

$ php artisan route:list | grep 'sample'
|        | GET|HEAD  | api/sample                               | front.api.                            | Closure                                                                      | api                                                                            |

この状態で CORS となるようにブラウザの Console 上でこの API を実行してみます。

fetch('https://test.smartkidsacademy.jp/api/sample', {method: 'GET', headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => console.log(response))
.catch(response => console.error(response))

// -->
// Access to fetch at 'https://dummy.jp/api/sample' from origin 'https://developer.mozilla.org' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

先程追加した Cors Middleware で設定しているはずの Access-Control-Allow-Origin が効いていません。

ブラウザの開発者ツールからこのときにリクエストの情報を見てみると

  1. プリフライトリクエストとして OPTIONS のリクエストが最初に飛ぶ
  2. その時のレスポンスヘッダーに Access-Control-Allow-Origin は含まれていない

である事がわかります。

OPTIONS に対応するルーティング定義は用意していない

php artisan route:list の結果からわかるように OPTIONS に対するルーティング定義は用意していません。
Laravel は対応していない HTTP リクエストメソッドに対しては 405 エラーを返しますが、そのエラーは発生していません。
このことから OPTIONS の場合は Laravel がプリフライトリクエストだからいい感じにレスポンスしてくれてると思われます。
ソースコードを grep してみたんですが、 OPTIONS ではいろいろな箇所がヒットして特定しきれなかったので諦めました。

Laravel がいい感じにレスポンスしてくれるときは Middleware が効かない

URL 自体はルーティング定義にある api/sample なので、 api Middleware グループを適用してほしいところですが、そこまではやってくれないようです。
試しに App\Http\Middleware\Cors に全然関係ない echo や exit を埋め込んでも動作に変化はありませんでした。

なので、レスポンスヘッダーに Access-Control-Allow-Origin が含まれることはありません。

対応方法

もうちょっとスマートな方法もあるきもしますが、ひとまず以下の方法で問題は解消できました。

  1. すべてのルーティングに Cors Middleware を適用する
  2. Cors Middleware 内で API Middleware グループを適用しようとしている URL であれば Access-Control-Allow-Origin をレスポンスヘッダーに含める

としました。

すべてのルーティングに Cors Middleware を適用する

App\Http\Kernel
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{

    :

    protected $middleware = [
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\Cors::class, // ★追加
    ];

    :

}

Cors Middleware 内で API Middleware グループを適用しようとしている URL であれば Access-Control-Allow-Origin をレスポンスヘッダーに含める

適用されている Middleware グループを取得できれば一番良かったんですが、どうにもうまく取れなかったので URL の一部から API であるかを判定するようにしています。
判定方法は実際の実装に合わせて柔軟に変更してください。

App\Http\Middleware\Cors
<?php

namespace App\Http\Middleware;

use Closure;

class Cors
{
    public function handle($request, Closure $next)
    {
        // すべてのレスポンスに CORS 用のヘッダーを追加する必要はないので URL から判断する
        $paths = explode('/', \Request::getPathInfo());
        if ($paths[1] === 'api') {
            return $next($request)
                ->header('Access-Control-Allow-Origin', '*')
                ->header('Access-Control-Allow-Methods', 'GET, POST')
                ->header('Access-Control-Allow-Headers', 'Accept, X-Requested-With, Origin, Content-Type');
        }
        return $next($request);
    }
}

再度 CORS となるようにブラウザの Console 上でこの API を実行してみる

今度はエラーが発生せず、正常に通信できるようになります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む