Docker

はじめてのコンテナ導入に向けて・DockerファイルとかPHPのiniファイルを読み込む・DebianでPHP7.4でLaravel

サービスの開発にコンテナを導入できていない状況がやばい!と思ってコンテナ導入やら何やらを試みるシリーズ。
実際にどんな感じなんだろう?と思ってDockerの事を理解する為に、下記の内容を実践してみる。

【超入門】20分でLaravel開発環境を爆速構築するDockerハンズオン

ハンズオン形式だけあって、実際に操作しながらでどんな感じかの内容を把握するのにぐっと役に立つ内容でした。
内容通りに行うと、コンテナの思想通りちゃんと環境が出来上がります!

自分が行ってて間際らしかったのが、Windows10 WSL2でDebian環境をつくっていたのでそこでもDebianが動いているし、コンテナ上でもDebianが動いていたのでちょっと混乱しました。
でも、そこで使用されているイメージが、debianを使われているんですね。納得、と。

合わせて
【連載】WSL2、Visual Studio Code、DockerでグッとよくなるWindows開発環境 〜 その4:Visual Studio Code、Dockerで改善!! 〜

こちらの記事内容のようにコンテナ上で動かしたいソースをVS Code で編集して、そのままGitでも編集できるようにしたい!と思いレッツ・トライ。

そして、今回はDockerの基礎も把握しつつコンテナ一台でLaravel動くようにしたいなーと思って下記のような構成にしてみよと思います。

├─.git
├─.devcontainer
│ ├Dockerfile
│ ├devcontainer.json
│ ├php.ini
│ └─php-fpm.d ※改めて見たらこの設定いらないかも
└─src
├─この配下にLaravelのディレクトリ

公式のイメージでドカンとつくる!と思ったらその公式のイメージ内でもいろんな処理が動いていて、その処理がどんな意味をもつのか分からないものだからいろんな壁にぶつかりまくりました。
コンテナはいっても仮想環境をつくるものだから一台のマシンをつくるようなものなんだな~

基本過ぎてあんまりわざわざ書いてないこと

Docker イメージ内の処理

COPY [コピーされる元] [コンテナイメージ内でコピーする場所]

コピーされる元がないと、コンテナを初回ビルドしよとした際に普通にエラーに。
コピーされる元はそのままだとBuildしようとしているDockerfileから見ての相対パスでの位置になるよう。

たまたまこのとき引っ掛かったファイルでエラー内容調べてたら、キャッシュ云々と書いてあったのでDocker DesktopをRestart\とかしてけど、全然見当違いでしたわ…

docker-composeして、VS CODEしたときどうなるの問題

VS Codeとか、そもそもイメージがどれ?となるからTerminalが開かない問題。
docker-compose.yml があるディレクトリを指定してそこからVS Codeでコンテナ立ち上げて、
ターミナル開こうとしたら開かず。
この空白の状態、というかそのときはホストOSも反応しないのかな?
docker-composeで、コンテナが複数ある場合はどのように構築・実装するといいんだろう?

.devcontanirディレクトリより上の階層のファイルはVS Codeで起動させたときに認識できないみたい

そりゃそうか?
という感じですね。

今回つくりたい環境

  • VS Code でGit 操作ができる
  • コンテナイメージにGCPを操作する Cloud SDKを設定しておきたい
  • HTTPアクセスしたいので、apacheが入っているイメージにしておく
    公式のイメージや参考にさせていただている

Docker コマンド

Dockerコンテナを起動、コンテナの中にログイン

docker run -i -t [イメージ名] /bin/bash

この[イメージ名]というのは、どこで指定しているんだろう?
FROM で指定するものの場合、このイメージ名が複数あったらどうするんだろう?
それとも、もしかしてそこで指定したイメージ名を元にDocker Hub からイメージを取得しに行っちゃうのかな?

Dockerfileはどこで出てくるのだろう?

「Dockerfile」ファイルは、プログラムのビルドでよく利用されるmakeツールの「Makefile」ファイルと同様に、Dockerコンテナーの構成内容をまとめて記述するシンプルなテキスト形式のファイルです。

一度ランしたイメージをはじめるときは

docker start [イメージ名]

になる?runしようとしたら、

Unable to find image 'vibrant_swirles:test' locally
docker: Error response from daemon: pull access denied for vibrant_swirles, repo
sitory does not exist or may require 'docker login': denied: requested access to
 the resource is denied.
See 'docker run --help'.

と言われ。

中に入る際は

docker exec -it [イメージ名] bash

実行したら中に入れた。
exec は  Docker 1.3 、2014年に追加されたようだから歴史はとても長いですね。
Bash、とやると「Bash セッションを作成します」という事になるので中に入るというBashコマンドを中で実行開始しますよ?
みたいなイメージ、ということですね。

オプション見ると -i 、-t はそれぞれあるけれど-itはなくない?
調べてみると

t -i など複数のオプションを指定する場合、まとめて -ti と指定できる。

とのこと。
それぞれ

|-i, –interactive=false | アタッチしていなくても STDIN をオープンにし続ける|
|-t, –tty=false |疑似ターミナル (pseudo-TTY) の割り当て|

と、なっているけれどもまた、説明が分かり辛い…
-iは、Keep STDIN open even if not attached
-tは、Allocate a pseudo-TTY

更に STDIN は standard input の略であると。

標準入力を開き続け、そこを操作可能な状態を維持する。
だから、手元の環境で、docker内入力出来る状態を続ける事が出来るのがこのコマンド、という事ですね。
コンテナの中で、bashを標準の入出力が見える形で操作できる状態を続けてくれる、という事。
なるほど!

ttyとは、標準入出力となっている端末デバイス(制御端末、controlling terminal)の名前を表示するUnix系のコマンドの事。
元来ttyとはteletypewriter(テレタイプライター)のことを言うそうです。

devcontainer.jsonとは?

これはVS Code用の設定ファイルだったのか。。

だから、Docker自体とはまた別ものになるわけね。
なるほど…

ひたすらVS Code でコンテナにアクセスしようとしたけれど、それはやっぱり遠回りになっていたような気がします…

今回の開発ではGAEで開発するので、下記のイメージをapache版にして開発してみる事にしました。
最強のLaravel開発環境をDockerを使って構築する【新編集版】

別途みると、ミドルウェアごとにコンテナ分けるメリットはそれはそれであるみたいなのですがそれはそれで。
ここでは焦らず、ゆっくり中の処理を見ていってみたいと思います。

PHP の variant

Dockerファイルで指定するイメージについても、

FROM php:7.4-apache ← このapache の部分ですね

いわゆる公式の中でもタグとしていろんな種類が用意されているみたいです。
PHPのイメージタグの種類としは

  • cli
  • apache
  • fpm
  • zts

の4種類が用意されている。
それぞれは下記の通り。

cli(Apacheを経由せず、直接コマンドライン上で実行)

ウェブサーバ用途ではない、使い捨てコンテナ他のイメージを構築するためのベースイメージ。

apache

ウェブサーバ(Apache mpm_prefork) + アプリケーションサーバ(Apache mod_php)の構成
PHPと組み合わせたDebianのApache httpdが含まれている

fpm(FastCGI Process Manager)

PHPを実行するアプリケーションサーバのみの構成。
FPM ( FastCGI Process Manager ) は PHP の FastCGI 実装のひとつで、 主に高負荷のサイトで有用な追加機能を用意してある。

FastCGIとは、Webサーバ上でユーザプログラムを動作させるためのインタフェース仕様の一つであると。
CGIの問題を解決するために Open Market社によって1990年代中頃に開発されたもの。

zts(phpがZend Thread Safetyでビルドされている)

マルチスレッド環境に対応するためのPHPの機構。
PHPはシングルスレッド環境(NTS)で動かす方が一般的です。

php.iniファイルの中身をしっかり読み解いてみる。
「INI」は「初期化」や「デフォルト設定」を意味する英語「initialization」から来ているとのこと。

そこで、今回の php.ini 設定の中をみていってみる。

;例外から生成されたスタックトレースに引数を含めたり、除外したりするための新しい INIディレクティブです。
zend.exception_ignore_args = off

;HTTPヘッダーにPHPのバージョンを出す(offにすると出さない)
expose_php = on

;PHPの実行時間を変更する。
;PHPの実行時間は、WEBサーバがリクエストを受け取りPHPに処理を開始したところから、PHPの処理が完了しレスポンスをWEBサーバに返すまでの時間
max_execution_time = 30

;一度にPOSTできる数の設定
max_input_vars = 1000

;1ファイルあたりの最大アップロードサイズ
upload_max_filesize = 64M

;POSTデータの最大サイズ
post_max_size = 128M

;スクリプトが確保できる最大メモリをバイト数で指定します。この命令は、 正しく書かれていないスクリプトがサーバーのメモリを食いつぶすことを防止するのに役立ちます。 もし、使用可能メモリに制限を設けたくない場合は、 ここに -1 を指定してください。
memory_limit = 256M

;PHPのエラー表示設定 E_ALLは全て表示する 
error_reporting = E_ALL

;ONにするとHTMLにPHPエラー内容を表示する
display_errors = on

;PHP起動時のエラーを表示する
display_startup_errors = on

;エラーログをファイルに残す
log_errors = on

;ログの出力先を設定します
error_log = /dev/stderr

;デフォルトの文字
default_charset = UTF-8

;タイムゾーン設定 TZ: "Asia/Tokyo"
[Date]
date.timezone = ${TZ}

;さまざまなメモリ統計情報の収集を有効にします。収集した情報には mysqli_get_client_stats() や ;mysqli_get_connection_stats() でアクセスでき、phpinfo()関数の出力の mysqlnd セクションにも表示されます。 

[mysqlnd]
mysqlnd.collect_memory_statistics = on


;1 にすると、アサーションのコードを生成して実行します (開発モード)。 0 にすると、アサーションのコードは生成しますが実行時にはスキップします (実行しません)。 -1 にすると、アサーションのコードを生成せず、アサーションのコストがゼロになる
;Assertion(アサーション)とは、「ここではこういった入力・結果がtrueである(つまりそれ以外は異常)」という前提条件を コード内に記述(=表明) することです。
[Assertion]
zend.assertions = 1

;mbstring で使用される言語設定(NLS)のデフォルト値を指定
[mbstring]
mbstring.language = Japanese

Zend FrameworkみたいにZendという単語を見かけるけど、「Zend」という名前の由来はphpの開発者の名前から来ているそう。
phpの発展に寄与した「ゼーブ・スラスキー(Zeev Suraski)」と「アンディ・ガトマンズ(Andi Gutmans)」の2人の名前(「Zeev」と「Andi」)を組み合わせて「Zend」を命名され、それでPHP関係のところでよくZendって見かけるんですね。

ここで、GAEとPHPってどうなるの?
php.ini ファイル
GAEは php.ini も設定できるみたいですね。

# Pull base image.FROM php:7.4-apache
#公式のphp:7.4があって、OSがDebianでapacheも入ったイメージ
FROM php:7.4-apache
表示する翻訳の優先順位
#SHELL 各種コマンドのシェル形式において用いられるデフォルトのシェルを、上書き設定するために利用されると。
# dockerfileでRUNさせる前に設定しておいた方が設定とのこと
#RUN で処理する内容が失敗した際に分かりやすくする的な・あんまり情報が
SHELL ["/bin/bash", "-oeux", "pipefail", "-c"]

# timezone environment
#環境変数を設定していく

#TZ:タイムゾーン UTCは世界標準時刻
#LANG ロケールの基本設定
#LC_ALL ロケール環境変数
#LANGUAGE 表示する翻訳の優先順位
#COMPOSER_ALLOW_SUPERUSER rootユーザーとして処理を実行
#COMPOSER_HOME HOMEディレクトリを指定
ENV TZ=UTC \
  # locale
  LANG=en_US.UTF-8 \
  LANGUAGE=en_US:en \
  LC_ALL=en_US.UTF-8 \
  # composer environment
  COMPOSER_ALLOW_SUPERUSER=1 \
  COMPOSER_HOME=/composer

#あれ?ここのコピー元のファイルつくっててエラーにならないな?
#これはマルチステージドビルドを行っているらしい
#ひとつの Dockerfile で複数のビルドができ,各ビルドの段階で必要な部分だけコピーして(残りは破棄される),最終的に使用したいベースイメージにペーストできる機能、とのこと

COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer

#パイプでつないてある
#apt-get update
#apt-get -y install git libicu-dev libonig-dev libzip-dev unzip locales
#以下、インストールする設定のライブラリ
# git おなじみ、Git
# libicu-dev(ICU は、堅牢で多機能な Unicode およびロケールへの対応を提供する C++ および C のライブラリ)、
# libonig-dev(モダンで柔軟な表示出力を行う為のライブラリ)
# unzip Zipを解凍・展開する為のライブラリ
# 多国語サポート (ロケール) 用 ライブラリ
#apt-get clean アーカイブファイルの削除
#rm -rf /var/lib/apt/lists/*  /var/lib/apt/lists/配下のファイルを全て削除
#locale-gen en_US.UTF-8  
#内部で localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8 を行っている事になるらしい?
#localedef コマンドは、ロケール依存情報 (照合、日付と時刻のフォーマット、および文字の属性など) の定義が入っているソース・ファイルを、実行時に使用するロケール・オブジェクト・ファイルに変換してくれる、と
#mkdir /var/run/php-fpm ディレクトリをつくる

#docker-php-ext-installは、コンテナイメージに事前に圧縮されて入っているエクステンションを操作し、インストールする
# intl phpの国際化用拡張モジュール
# pdo_mysql PHP から MySQL データベースへのアクセスを可能にするための PHP Data Objects (PDO) インターフェイス を実装したドライバです。※今回はMySQLを使用する事は想定していないからいらないかもな
#zip 機能をインストール
#bcmath`拡張機能・任意精度数学関数?
#composer config -g process-timeout composerのタイムアウト時間を設定 -gはグローバル
#composer config -g repos.packagist composer https://packagist.org
#hirakさんが作成した日本国内のサーバーからインストールするよう設定

RUN apt-get update && \ 
  apt-get -y install git libicu-dev libonig-dev libzip-dev unzip locales && \
  apt-get clean && \
  rm -rf /var/lib/apt/lists/* && \
  locale-gen en_US.UTF-8 && \
  localedef -f UTF-8 -i en_US en_US.UTF-8 && \
  mkdir /var/run/php-fpm && \
  docker-php-ext-install intl pdo_mysql zip bcmath && \
  composer config -g process-timeout 3600 && \
  composer config -g repos.packagist composer https://packagist.org

# あらかじめホストOS上で作成していた必要なファイルをコンテナ内にコピー
#php-fpmのインストール。Nginxと連携する際に必要?今回はいらないか...
#PHPの設定ファイルである、iniファイルを設定
#COPY ./infra/docker/php/php-fpm.d/zzz-www.conf /usr/local/etc/php-fpm.d/zzz-www.conf
COPY ./infra/docker/php/php.ini /usr/local/etc/php/php.ini

#Google Cloud SDKをインストールする gnupg2が必要だった/本来、上の階層と組み合わせていいんだろうな
#通信とデータ保存を安全なものにする GNU ツール
RUN apt-get update && apt-get install -y gnupg2

#&&は処理を続けて行うことができる
#tee -a でファイルに追記する
#「apt-key」「apt」が パッケージの認証に使用するキーの一覧を管理する
#--keyring [ファイル名]  これにより、コマンドが操作するべき特定のキーリングファイルを指定できる
#curl https://packages.cloud.google.com/apt/doc/apt-key.gpg
#curlは様々なプロトコルを使用してデータ転送を行うことができるコマンド 上記の場合ダウンロードしてる?
#add - とする事で標準入力から読み込む。 add [ファイル名] 
#google-cloud-sdk これらの流れを用いて、google-cloud-sdkをインストール
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg  add - && apt-get update -y && apt-get install google-cloud-sdk -y

COPY ./php.ini /usr/local/etc/php/php.ini

WORKDIR /work

こうして読み解いたらNginxを使用しない場合 php-fpm の処理はいらなかったですね…

参考になりそうなコンテンツ

Debianの公式サイト

と、まあ、ここまで参考サイトを参考にDockerコンテナを活用するにあたって基本の基本から見ていきましたけれどこうして見ていくと改めて知ることが多いですね。

また、次はLaravelとかの設定を行っていってみたいと思います。

%d人のブロガーが「いいね」をつけました。