Sep 4, 2021
Sep 5, 2021
N/A Views
MD
warning
この記事は2年以上前に更新されたものです。情報が古くなっている可能性があります。

Paketo BuildpacksでPHPのコンテナイメージを作成するメモ。使用する pack CLIのバージョンは次の通りです。

$ pack version
0.20.0+git-66a4f32.build-2668

参考にしたドキュメントは次の通りです。

目次

Hello World

まずは一番簡単なPHPアプリを作成。

Paketo Buildpackではデフォルトでhtdocsが公開ディレクトリ。

mkdir -p hello-php/htdocs
cat <<EOF > hello-php/htdocs/index.php
<?php echo 'Hello World! (PHP ' . phpversion() . ')';
EOF

使用するBuilderはpaketobuildpacks/builder:full。次のコマンドでイメージを作成します。

pack build ghcr.io/making/hello-php --builder paketobuildpacks/builder:full --path hello-php

ビルドログは次の通り。

full: Pulling from paketobuildpacks/builder
Digest: sha256:5815bb199fb92e21bae058df56416ab6e2a0a85609865b85c0bcfa8cbc56625e
Status: Image is up to date for paketobuildpacks/builder:full
full-cnb: Pulling from paketobuildpacks/run
Digest: sha256:fac2ca83109101e0d1dd8c26707f5f58e05ccf52b2c42db95e25bda86b9887b2
Status: Image is up to date for paketobuildpacks/run:full-cnb
===> DETECTING
Warning: Warning: buildpack paketo-buildpacks/php-web has a "version" key. This key is deprecated in build plan requirements in buildpack API 0.3. "metadata.version" should be used instead
3 of 9 buildpacks participating
paketo-buildpacks/ca-certificates 2.4.0
paketo-buildpacks/php-dist        0.3.3
paketo-buildpacks/php-web         0.1.2
===> ANALYZING
Previous image with name "ghcr.io/making/hello-php" not found
===> RESTORING
===> BUILDING

Paketo CA Certificates Buildpack 2.4.0
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Paketo PHP Distribution Buildpack 0.3.3
  Resolving PHP version
    Candidate version sources (in priority order):
      default-versions -> "7.4.*"

    Selected PHP version (using default-versions): 7.4.23

  Executing build process
    Installing PHP 7.4.23
      Completed in 2.139s

  Configuring environment
    MIBDIRS           -> "/layers/paketo-buildpacks_php-dist/php/mibs"
    PATH              -> "/layers/paketo-buildpacks_php-dist/php/sbin:$PATH"
    PHP_API           -> "20190902"
    PHP_EXTENSION_DIR -> "/layers/paketo-buildpacks_php-dist/php/lib/php/extensions/no-debug-non-zts-20190902"
    PHP_HOME          -> "/layers/paketo-buildpacks_php-dist/php"


Paketo PHP Web Buildpack 0.1.2
  PHP Web 6e8855d5fb50668eec565ef7b9f113b121b2a5597852389e434c9b9d18743739: Contributing to layer
  Configuring PHP Application
    Using feature -- PHP
    Writing PHPRC to shared
    Writing PHP_INI_SCAN_DIR to shared
    Using feature -- PHP Web Server
  Process types:
    task: php -S 0.0.0.0:$PORT -t /workspace/htdocs
    web:  php -S 0.0.0.0:$PORT -t /workspace/htdocs
===> EXPORTING
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/php-dist:php'
Adding layer 'paketo-buildpacks/php-web:php-web'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving ghcr.io/making/hello-php...
*** Images (d3add6bf54df):
      ghcr.io/making/hello-php
Adding cache layer 'paketo-buildpacks/php-dist:php'
Successfully built image ghcr.io/making/hello-php

作成したイメージを実行します。環境変数PORTでポートを指定しないといけないです。

$ docker run --rm -e PORT=8080 -p 8080:8080 ghcr.io/making/hello-php
[Sat Sep  4 14:58:39 2021] PHP 7.4.23 Development Server (http://0.0.0.0:8080) started

組み込みサーバーが起動しました。アクセスしてみます。

$ curl http://localhost:8080
Hello World! (PHP 7.4.23)

サポートされるPHPのバージョンとデフォルトのバージョンはPHP Distribution Buildpackのバージョンに依存します。
今回はPHP Distribution Buildpack 0.3.3が使用されているので、このバージョンをリリースノート
https://github.com/paketo-buildpacks/php-dist/releases/tag/v0.3.3
を確認すると、デフォルトが7.4.*で、そのほか7.3.*8.0.*の最新バージョンと一つ前のバージョンがサポートされていることがわかります。

PHPのバージョンを変更する

PHPのバージョンを指定したい場合は、buildpack.ymlにバージョンを指定します。PHP 8.0に変更してみます。

cat <<EOF > hello-php/buildpack.yml
---
php:
  version: 8.0.*
EOF

再度ビルドします。

pack build ghcr.io/making/hello-php --builder paketobuildpacks/builder:full --path hello-php

ビルドログは次の通り。PHP 8.0がインストールされていることがわかります。

full: Pulling from paketobuildpacks/builder
Digest: sha256:5815bb199fb92e21bae058df56416ab6e2a0a85609865b85c0bcfa8cbc56625e
Status: Image is up to date for paketobuildpacks/builder:full
full-cnb: Pulling from paketobuildpacks/run
Digest: sha256:fac2ca83109101e0d1dd8c26707f5f58e05ccf52b2c42db95e25bda86b9887b2
Status: Image is up to date for paketobuildpacks/run:full-cnb
===> DETECTING
Warning: Warning: buildpack paketo-buildpacks/php-web has a "version" key. This key is deprecated in build plan requirements in buildpack API 0.3. "metadata.version" should be used instead
3 of 9 buildpacks participating
paketo-buildpacks/ca-certificates 2.4.0
paketo-buildpacks/php-dist        0.3.3
paketo-buildpacks/php-web         0.1.2
===> ANALYZING
Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
Restoring metadata for "paketo-buildpacks/php-dist:php" from app image
Restoring metadata for "paketo-buildpacks/php-web:php-web" from app image
===> RESTORING
Restoring data for "paketo-buildpacks/php-dist:php" from cache
===> BUILDING

Paketo CA Certificates Buildpack 2.4.0
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Reusing cached layer
Paketo PHP Distribution Buildpack 0.3.3
  Resolving PHP version
    Candidate version sources (in priority order):
      buildpack.yml    -> "8.0.*"
      default-versions -> "7.4.*"

    Selected PHP version (using buildpack.yml): 8.0.10

  Executing build process
    Installing PHP 8.0.10
      Completed in 5.065s

  Configuring environment
    MIBDIRS           -> "/layers/paketo-buildpacks_php-dist/php/mibs"
    PATH              -> "/layers/paketo-buildpacks_php-dist/php/sbin:$PATH"
    PHP_API           -> "20200930"
    PHP_EXTENSION_DIR -> "/layers/paketo-buildpacks_php-dist/php/lib/php/extensions/no-debug-non-zts-20200930"
    PHP_HOME          -> "/layers/paketo-buildpacks_php-dist/php"


Paketo PHP Web Buildpack 0.1.2
  PHP Web c49b83a4f6a804a8611e69ad754c76cf62cb509a4b546bbe6ed50c950ec52a61: Contributing to layer
  Configuring PHP Application
    Using feature -- PHP
    Writing PHPRC to shared
    Writing PHP_INI_SCAN_DIR to shared
    Using feature -- PHP Web Server
  Process types:
    task: php -S 0.0.0.0:$PORT -t /workspace/htdocs
    web:  php -S 0.0.0.0:$PORT -t /workspace/htdocs
===> EXPORTING
Reusing layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/php-dist:php'
Adding layer 'paketo-buildpacks/php-web:php-web'
Adding 1/1 app layer(s)
Reusing layer 'launcher'
Adding layer 'config'
Reusing layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving ghcr.io/making/hello-php...
*** Images (74e4981ac54c):
      ghcr.io/making/hello-php
Adding cache layer 'paketo-buildpacks/php-dist:php'
Successfully built image ghcr.io/making/hello-php

実行します。

$ docker run --rm -e PORT=8080 -p 8080:8080 ghcr.io/making/hello-php
[Sat Sep  4 15:08:16 2021] PHP 8.0.10 Development Server (http://0.0.0.0:8080) started

組み込みサーバーが起動しました。アクセスしてみます。

$ curl http://localhost:8080
Hello World! (PHP 8.0.10)

WebサーバーをApache HTTP Serverに変更する

Webサーバーを組み込みサーバーからApache HTTP Serverに変更したい場合もbuildpack.ymlに指定すれば良いです。

cat <<EOF > hello-php/buildpack.yml
---
php:
  webserver: httpd
EOF

再度ビルドします。

pack build ghcr.io/making/hello-php --builder paketobuildpacks/builder:full --path hello-php

ビルドログは次の通り。Apache HTTP Serverがインストールされていることがわかります。

full: Pulling from paketobuildpacks/builder
Digest: sha256:5815bb199fb92e21bae058df56416ab6e2a0a85609865b85c0bcfa8cbc56625e
Status: Image is up to date for paketobuildpacks/builder:full
full-cnb: Pulling from paketobuildpacks/run
Digest: sha256:fac2ca83109101e0d1dd8c26707f5f58e05ccf52b2c42db95e25bda86b9887b2
Status: Image is up to date for paketobuildpacks/run:full-cnb
===> DETECTING
Warning: Warning: buildpack paketo-buildpacks/php-web has a "version" key. This key is deprecated in build plan requirements in buildpack API 0.3. "metadata.version" should be used instead
4 of 9 buildpacks participating
paketo-buildpacks/ca-certificates 2.4.0
paketo-buildpacks/httpd           0.1.1
paketo-buildpacks/php-dist        0.3.3
paketo-buildpacks/php-web         0.1.2
===> ANALYZING
Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
Restoring metadata for "paketo-buildpacks/php-dist:php" from app image
Restoring metadata for "paketo-buildpacks/php-web:php-web" from app image
===> RESTORING
Restoring data for "paketo-buildpacks/php-dist:php" from cache
===> BUILDING

Paketo CA Certificates Buildpack 2.4.0
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Reusing cached layer
Paketo Apache HTTP Server Buildpack 0.1.1
  Resolving Apache HTTP Server version
    Candidate version sources (in priority order):
      <unknown> -> ""

    Selected Apache HTTP Server version (using <unknown>): 2.4.48

  Executing build process
    Installing Apache HTTP Server 2.4.48
      Completed in 398ms

  Configuring environment
    APP_ROOT    -> "/workspace"
    SERVER_ROOT -> "/layers/paketo-buildpacks_httpd/httpd"
Paketo PHP Distribution Buildpack 0.3.3
  Resolving PHP version
    Candidate version sources (in priority order):
      default-versions -> "7.4.*"

    Selected PHP version (using default-versions): 7.4.23

  Executing build process
    Installing PHP 7.4.23
      Completed in 2.302s

  Configuring environment
    MIBDIRS           -> "/layers/paketo-buildpacks_php-dist/php/mibs"
    PATH              -> "/layers/paketo-buildpacks_php-dist/php/sbin:$PATH"
    PHP_API           -> "20190902"
    PHP_EXTENSION_DIR -> "/layers/paketo-buildpacks_php-dist/php/lib/php/extensions/no-debug-non-zts-20190902"
    PHP_HOME          -> "/layers/paketo-buildpacks_php-dist/php"


Paketo PHP Web Buildpack 0.1.2
  PHP Web 760228aff8ac402e7946d261215b234fa88226d4a7c4dbca78642386368eb24f: Contributing to layer
  Configuring PHP Application
    Using feature -- PHP
    Writing PHPRC to shared
    Writing PHP_INI_SCAN_DIR to shared
    Using feature -- Apache Web Server
    Using feature -- PhpFpm
    Using feature -- ProcMgr
  Process types:
    web: procmgr /layers/paketo-buildpacks_php-web/php-web/procs.yml
===> EXPORTING
Reusing layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/httpd:httpd'
Adding layer 'paketo-buildpacks/php-dist:php'
Adding layer 'paketo-buildpacks/php-web:php-web'
Adding 1/1 app layer(s)
Reusing layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving ghcr.io/making/hello-php...
*** Images (0899054ad05f):
      ghcr.io/making/hello-php
Adding cache layer 'paketo-buildpacks/php-dist:php'
Successfully built image ghcr.io/making/hello-php

実行します。

$ docker run --rm -e PORT=8080 -p 8080:8080 ghcr.io/making/hello-php
[04-Sep-2021 15:14:17] NOTICE: fpm is running, pid 23
[04-Sep-2021 15:14:17] NOTICE: ready to handle connections
[Sat Sep 04 15:14:17.224008 2021] [mpm_event:notice] [pid 24:tid 139634204366720] AH00489: Apache/2.4.48 (Unix) configured -- resuming normal operations
[Sat Sep 04 15:14:17.224099 2021] [mpm_event:info] [pid 24:tid 139634204366720] AH00490: Server built: Jun  2 2021 01:19:36
[Sat Sep 04 15:14:17.224132 2021] [core:notice] [pid 24:tid 139634204366720] AH00094: Command line: 'httpd -f /workspace/httpd.conf -D FOREGROUND'

Apache HTTP Serverが起動しました。アクセスしてみます。

$ curl http://localhost:8080
Hello World! (PHP 7.4.23)

HTTPDのカスタマイズ例はこちら

https://github.com/paketo-buildpacks/php-web/tree/main/integration/testdata/simple_app_custom_httpd_cfg

WebサーバーをNginxに変更する

Webサーバーを組み込みサーバーからNginxに変更したい場合もbuildpack.ymlに指定すれば良いです。

cat <<EOF > hello-php/buildpack.yml
---
php:
  webserver: nginx
EOF

再度ビルドします。

pack build ghcr.io/making/hello-php --builder paketobuildpacks/builder:full --path hello-php

ビルドログは次の通り。Nginxがインストールされていることがわかります。

full: Pulling from paketobuildpacks/builder
Digest: sha256:5815bb199fb92e21bae058df56416ab6e2a0a85609865b85c0bcfa8cbc56625e
Status: Image is up to date for paketobuildpacks/builder:full
full-cnb: Pulling from paketobuildpacks/run
Digest: sha256:fac2ca83109101e0d1dd8c26707f5f58e05ccf52b2c42db95e25bda86b9887b2
Status: Image is up to date for paketobuildpacks/run:full-cnb
===> DETECTING
Warning: Warning: buildpack paketo-buildpacks/php-web has a "version" key. This key is deprecated in build plan requirements in buildpack API 0.3. "metadata.version" should be used instead
4 of 9 buildpacks participating
paketo-buildpacks/ca-certificates 2.4.0
paketo-buildpacks/nginx           0.3.2
paketo-buildpacks/php-dist        0.3.3
paketo-buildpacks/php-web         0.1.2
===> ANALYZING
Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
Restoring metadata for "paketo-buildpacks/php-dist:php" from app image
Restoring metadata for "paketo-buildpacks/php-web:php-web" from app image
===> RESTORING
Restoring data for "paketo-buildpacks/php-dist:php" from cache
===> BUILDING

Paketo CA Certificates Buildpack 2.4.0
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Reusing cached layer
Paketo Nginx Server Buildpack 0.3.2
  Resolving Nginx Server version
    Candidate version sources (in priority order):
      <unknown> -> "*"

    Selected Nginx Server version (using <unknown>): 1.21.1

  Executing build process
    Installing Nginx Server 1.21.1
      Completed in 800ms

  Configuring environment
    PATH -> "$PATH:/layers/paketo-buildpacks_nginx/nginx/sbin"
        Writing profile.d/configure.sh
      Calls executable that parses templates in nginx conf
Paketo PHP Distribution Buildpack 0.3.3
  Resolving PHP version
    Candidate version sources (in priority order):
      default-versions -> "7.4.*"

    Selected PHP version (using default-versions): 7.4.23

  Reusing cached layer /layers/paketo-buildpacks_php-dist/php


Paketo PHP Web Buildpack 0.1.2
  PHP Web 41eacd0c9c1e4af1d92dde54e79a5ea4d0c0e8daca9baf6c8fe74ac30c0875e9: Contributing to layer
  Configuring PHP Application
    Using feature -- PHP
    Writing PHPRC to shared
    Writing PHP_INI_SCAN_DIR to shared
    Using feature -- Nginx
    Using feature -- PhpFpm
    Using feature -- ProcMgr
  Process types:
    web: procmgr /layers/paketo-buildpacks_php-web/php-web/procs.yml
===> EXPORTING
Reusing layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/nginx:nginx'
Reusing layer 'paketo-buildpacks/php-dist:php'
Adding layer 'paketo-buildpacks/php-web:php-web'
Adding 1/1 app layer(s)
Reusing layer 'launcher'
Adding layer 'config'
Reusing layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving ghcr.io/making/hello-php...
*** Images (8e07ef90b035):
      ghcr.io/making/hello-php
Reusing cache layer 'paketo-buildpacks/php-dist:php'
Successfully built image ghcr.io/making/hello-php

実行します。

$ docker run --rm -e PORT=8080 -p 8080:8080 ghcr.io/making/hello-php
2021/09/04 15:18:33 [notice] 29#0: using the "epoll" event method
2021/09/04 15:18:33 [notice] 29#0: nginx/1.21.1
2021/09/04 15:18:33 [notice] 29#0: built by gcc 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) 
2021/09/04 15:18:33 [notice] 29#0: OS: Linux 5.10.25-linuxkit
2021/09/04 15:18:33 [notice] 29#0: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/09/04 15:18:33 [notice] 29#0: start worker processes
2021/09/04 15:18:33 [notice] 29#0: start worker process 31
2021/09/04 15:18:33 [notice] 29#0: start worker process 32
2021/09/04 15:18:33 [notice] 29#0: start worker process 33
2021/09/04 15:18:33 [notice] 29#0: start worker process 34
[04-Sep-2021 15:18:33] NOTICE: fpm is running, pid 30
[04-Sep-2021 15:18:33] NOTICE: ready to handle connections

Nginxが起動しました。アクセスしてみます。

$ curl http://localhost:8080
Hello World! (PHP 7.4.23)

Nginxのカスタマイズ例はこちら

https://github.com/paketo-buildpacks/php-web/tree/main/integration/testdata/simple_app_nginx_custom_cfg

拡張モジュールを追加する

デフォルトで有効になっていない拡張モジュールを追加する例としてRedisを使用します。

mkdir -p hello-redis/htdocs
cat <<'EOF' > hello-redis/htdocs/index.php
<?php
$redis = new Redis();
$redis->connect(getenv('REDIS_HOST'), getenv('REDIS_PORT'));
echo $redis->ping();
EOF

まずはそのままビルドします。

pack build ghcr.io/making/hello-redis --builder paketobuildpacks/builder:full --path hello-redis

実行します。この時点でエラーは出ません。

$ docker run --rm -e PORT=8080 -e REDIS_HOST=host.docker.internal -e REDIS_PORT=6379 -p 8080:8080 ghcr.io/making/hello-redis
[Sat Sep  4 16:16:06 2021] PHP 7.4.23 Development Server (http://0.0.0.0:8080) started

アクセスしてみます。

curl http://localhost:8080

サーバーで実行時エラーが出力されます。

[Sat Sep  4 16:18:26 2021] 172.17.0.1:64374 Accepted
[Sat Sep  4 16:18:26 2021] PHP Fatal error:  Uncaught Error: Class 'Redis' not found in /workspace/htdocs/index.php:2
Stack trace:
#0 {main}
  thrown in /workspace/htdocs/index.php on line 2
[Sat Sep  4 16:18:26 2021] 172.17.0.1:64374 [500]: GET / - Uncaught Error: Class 'Redis' not found in /workspace/htdocs/index.php:2
Stack trace:
#0 {main}
  thrown in /workspace/htdocs/index.php on line 2
[Sat Sep  4 16:18:26 2021] 172.17.0.1:64374 Closing

lass 'Redis' not foundと言われているので拡張モジュールがロードされていません。

拡張モジュールを追加するには.php.dディレクトリを作成してその中に任意の.iniファイルを作成して.soファイルを記述すれば良いです。

mkdir hello-redis/.php.ini.d
cat <<EOF > hello-redis/.php.ini.d/extension.ini 
extension=redis.so
EOF

再度ビルドします。

pack build ghcr.io/making/hello-redis --builder paketobuildpacks/builder:full --path hello-redis 

実行します。

$ docker run --rm -e PORT=8080 -e REDIS_HOST=host.docker.internal -e REDIS_PORT=6379 -p 8080:8080 ghcr.io/making/hello-redis
[Sat Sep  4 16:23:01 2021] PHP Warning:  Cannot load module 'redis' because required module 'igbinary' is not loaded in Unknown on line 0
[Sat Sep  4 16:23:01 2021] PHP 7.4.23 Development Server (http://0.0.0.0:8080) started

igbinaryモジュールがないからredisモジュールがロードできないというワーニングが出ているのでextension.iniを更新します。

cat <<EOF > hello-redis/.php.ini.d/extension.ini 
extension=redis.so
extension=igbinary.so
EOF

再度ビルドします。

pack build ghcr.io/making/hello-redis --builder paketobuildpacks/builder:full --path hello-redis 

実行します。

$ docker run --rm -e PORT=8080 -e REDIS_HOST=host.docker.internal -e REDIS_PORT=6379 -p 8080:8080 ghcr.io/making/hello-redis 
[Sat Sep  4 16:25:49 2021] PHP 7.4.23 Development Server (http://0.0.0.0:8080) started

起動しました。アクセスします。

$ curl http://localhost:8080
1

レスポンスが無事返りました。

Laravelを使う

PHPのデファクトスタンダードなフレームワークであるLaravelで作られたアプリのコンテナイメージを作成します。

brew install composer
composer global require laravel/installer
export PATH=$HOME/.composer/vendor/bin:$PATH
laravel new hello-laravel --git

Composerが使われている場合、composer.jsonに設定されているPHPバージョンとの整合性チェックが行われます。

$ ls -l hello-laravel 
total 600
-rw-r--r--   1 toshiaki  wheel    3964 Aug 25 00:59 README.md
drwxr-xr-x   7 toshiaki  wheel     224 Aug 25 00:59 app
-rwxr-xr-x   1 toshiaki  wheel    1686 Aug 25 00:59 artisan
drwxr-xr-x   4 toshiaki  wheel     128 Aug 25 00:59 bootstrap
-rw-r--r--   1 toshiaki  wheel    1735 Aug 25 00:59 composer.json
-rw-r--r--   1 toshiaki  wheel  273409 Sep  5 01:35 composer.lock
drwxr-xr-x  17 toshiaki  wheel     544 Aug 25 00:59 config
drwxr-xr-x   6 toshiaki  wheel     192 Aug 25 00:59 database
-rw-r--r--   1 toshiaki  wheel     473 Aug 25 00:59 package.json
-rw-r--r--   1 toshiaki  wheel    1202 Aug 25 00:59 phpunit.xml
drwxr-xr-x   7 toshiaki  wheel     224 Aug 25 00:59 public
drwxr-xr-x   6 toshiaki  wheel     192 Aug 25 00:59 resources
drwxr-xr-x   6 toshiaki  wheel     192 Aug 25 00:59 routes
-rw-r--r--   1 toshiaki  wheel     563 Aug 25 00:59 server.php
drwxr-xr-x   5 toshiaki  wheel     160 Aug 25 00:59 storage
drwxr-xr-x   6 toshiaki  wheel     192 Aug 25 00:59 tests
drwxr-xr-x  43 toshiaki  wheel    1376 Sep  5 01:35 vendor
-rw-r--r--   1 toshiaki  wheel     559 Aug 25 00:59 webpack.mix.js

$ cat hello-laravel/composer.json | grep '"php"'
        "php": "^7.3|^8.0",

今回の例では7.3か8.0のみサポートされており、Buildpackのデフォルトである7.4と合わないため、buildpack.ymlに使用するPHPのバージョンを明示します。
また生成された公開ディレクトリはpublicなので、これもbuildpack.yml

cat <<EOF > hello-laravel/buildpack.yml
---
php:
  version: 7.3.*
  webdirectory: public
EOF

ビルドします。package.jsonがあるため、そのまま実行するとNode.jsアプリと検出され、PHPのインストールが行われません。
Node.js BuildpackとPHP Buildpack両方が使用されるように--buildpackオプションを指定します。最後に指定したBuildpackが起動用に使用されます。

$ pack build ghcr.io/making/hello-laravel --builder paketobuildpacks/builder:full --path hello-laravel --buildpack paketo-buildpacks/nodejs --buildpack paketo-buildpacks/php
full: Pulling from paketobuildpacks/builder
Digest: sha256:5815bb199fb92e21bae058df56416ab6e2a0a85609865b85c0bcfa8cbc56625e
Status: Image is up to date for paketobuildpacks/builder:full
full-cnb: Pulling from paketobuildpacks/run
Digest: sha256:fac2ca83109101e0d1dd8c26707f5f58e05ccf52b2c42db95e25bda86b9887b2
Status: Image is up to date for paketobuildpacks/run:full-cnb
===> DETECTING
Warning: Warning: buildpack paketo-buildpacks/php-composer has a "version" key. This key is deprecated in build plan requirements in buildpack API 0.3. "metadata.version" should be used instead
Warning: Warning: buildpack paketo-buildpacks/php-web has a "version" key. This key is deprecated in build plan requirements in buildpack API 0.3. "metadata.version" should be used instead
8 of 14 buildpacks participating
paketo-buildpacks/ca-certificates 2.4.0
paketo-buildpacks/node-engine     0.7.1
paketo-buildpacks/npm-install     0.4.0
paketo-buildpacks/node-module-bom 0.1.1
paketo-buildpacks/npm-start       0.3.0
paketo-buildpacks/php-dist        0.3.3
paketo-buildpacks/php-composer    0.2.2
paketo-buildpacks/php-web         0.1.2
===> ANALYZING
Previous image with name "ghcr.io/making/hello-laravel" not found
Restoring metadata for "paketo-buildpacks/node-module-bom:cyclonedx-node-module" from cache
Restoring metadata for "paketo-buildpacks/php-composer:be95557cc36eeb82da0f4340a469bad56b57f742d2891892dcb2f8b0179790ec" from cache
Restoring metadata for "paketo-buildpacks/php-composer:php-composer-cache" from cache
===> RESTORING
Restoring data for "paketo-buildpacks/node-module-bom:cyclonedx-node-module" from cache
Restoring data for "paketo-buildpacks/php-composer:be95557cc36eeb82da0f4340a469bad56b57f742d2891892dcb2f8b0179790ec" from cache
Restoring data for "paketo-buildpacks/php-composer:php-composer-cache" from cache
===> BUILDING

Paketo CA Certificates Buildpack 2.4.0
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Paketo Node Engine Buildpack 0.7.1
  Resolving Node Engine version
    Candidate version sources (in priority order):
                -> ""
      <unknown> -> ""

    Selected Node Engine version (using ): 14.17.6

  Executing build process
    Installing Node Engine 14.17.6
      Completed in 1.795s

  Configuring build environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/paketo-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

  Configuring launch environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/paketo-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

    Writing profile.d/0_memory_available.sh
      Calculates available memory based on container limits at launch time.
      Made available in the MEMORY_AVAILABLE environment variable.

Paketo NPM Install Buildpack 0.4.0
  Resolving installation process
    Process inputs:
      node_modules      -> "Not found"
      npm-cache         -> "Not found"
      package-lock.json -> "Not found"

    Selected NPM build process: 'npm install'

  Executing build process
    Running 'npm install --unsafe-perm --cache /layers/paketo-buildpacks_npm-install/npm-cache'
      Completed in 15.962s

  Configuring launch environment
    NPM_CONFIG_LOGLEVEL -> "error"

  Configuring environment shared by build and launch
    PATH -> "$PATH:/layers/paketo-buildpacks_npm-install/modules/node_modules/.bin"


Paketo Node Module Bill of Materials Generator Buildpack 0.1.1
  Resolving CycloneDX Node.js Module version
    Selected CycloneDX Node.js Module version: 3.0.6

  Reusing cached layer /layers/paketo-buildpacks_node-module-bom/cyclonedx-node-module

  Configuring environment
    Appending CycloneDX Node.js Module onto PATH

  Running CycloneDX Node.js Module
    Running 'cyclonedx-bom -o bom.json'
      Completed in 270ms

Paketo NPM Start Buildpack 0.3.0
  Assigning launch processes
    web: node server.js

Paketo PHP Distribution Buildpack 0.3.3
  Resolving PHP version
    Candidate version sources (in priority order):
      buildpack.yml    -> "7.3.*"
      composer.lock    -> "^7.3|^8.0"
      default-versions -> "7.4.*"

    Selected PHP version (using buildpack.yml): 7.3.30

  Executing build process
    Installing PHP 7.3.30
      Completed in 3.007s

  Configuring environment
    MIBDIRS           -> "/layers/paketo-buildpacks_php-dist/php/mibs"
    PATH              -> "/layers/paketo-buildpacks_php-dist/php/sbin:$PATH"
    PHP_API           -> "20180731"
    PHP_EXTENSION_DIR -> "/layers/paketo-buildpacks_php-dist/php/lib/php/extensions/no-debug-non-zts-20180731"
    PHP_HOME          -> "/layers/paketo-buildpacks_php-dist/php"


Paketo PHP Composer Buildpack 0.2.2
   2.1.5: Contributing to layer
    Reusing cached download from previous build
    Expanding to /layers/paketo-buildpacks_php-composer/composer
  PHP Composer Cache 96ebbb5c8694dd2c33b07ca6d40c10b0b670bc10176d2507d8b3b4a739d46f01: Reusing cached layer
Checking platform requirements for packages in the vendor dir
  PHP Composer 0a07c8a562dc6c59f9c2cba99152272526f688dd9bd63efeeabb62fe7569615b: Contributing to layer
Installing dependencies from lock file
Verifying lock file contents can be installed on current platform.
Package operations: 0 installs, 0 updates, 40 removals
  - Removing theseer/tokenizer (1.2.1)
  - Removing sebastian/version (3.0.2)
  - Removing sebastian/type (2.3.4)
  - Removing sebastian/resource-operations (3.0.3)
  - Removing sebastian/recursion-context (4.0.4)
  - Removing sebastian/object-reflector (2.0.4)
  - Removing sebastian/object-enumerator (4.0.4)
  - Removing sebastian/lines-of-code (1.0.3)
  - Removing sebastian/global-state (5.0.3)
  - Removing sebastian/exporter (4.0.3)
  - Removing sebastian/environment (5.1.3)
  - Removing sebastian/diff (4.0.4)
  - Removing sebastian/complexity (2.0.2)
  - Removing sebastian/comparator (4.0.6)
  - Removing sebastian/code-unit-reverse-lookup (2.0.3)
  - Removing sebastian/code-unit (1.0.8)
  - Removing sebastian/cli-parser (1.0.1)
  - Removing phpunit/phpunit (9.5.9)
  - Removing phpunit/php-timer (5.0.3)
  - Removing phpunit/php-text-template (2.0.4)
  - Removing phpunit/php-invoker (3.1.1)
  - Removing phpunit/php-file-iterator (3.0.5)
  - Removing phpunit/php-code-coverage (9.2.6)
  - Removing phpspec/prophecy (1.13.0)
  - Removing phpdocumentor/type-resolver (1.4.0)
  - Removing phpdocumentor/reflection-docblock (5.2.2)
  - Removing phpdocumentor/reflection-common (2.2.0)
  - Removing phar-io/version (3.1.0)
  - Removing phar-io/manifest (2.0.3)
  - Removing nunomaduro/collision (v5.9.0)
  - Removing myclabs/deep-copy (1.10.2)
  - Removing mockery/mockery (1.4.3)
  - Removing laravel/sail (v1.10.1)
  - Removing hamcrest/hamcrest-php (v2.0.1)
  - Removing filp/whoops (2.14.1)
  - Removing fakerphp/faker (v1.15.0)
  - Removing facade/ignition-contracts (1.0.2)
  - Removing facade/ignition (2.12.0)
  - Removing facade/flare-client-php (1.8.1)
  - Removing doctrine/instantiator (1.4.0)
Package sebastian/resource-operations is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Package manifest generated successfully.
47 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

Paketo PHP Web Buildpack 0.1.2
  PHP Web b684f3e8d951036f5c031a2d53ee2c672557a7f28f1129e6cb7afc90a71c05f0: Contributing to layer
  Configuring PHP Application
    Using feature -- PHP
    Writing PHPRC to shared
    Writing PHP_INI_SCAN_DIR to shared
    Using feature -- PHP Web Server
  Process types:
    task: php -S 0.0.0.0:$PORT -t /workspace/public
    web:  php -S 0.0.0.0:$PORT -t /workspace/public
===> EXPORTING
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/node-engine:node'
Adding layer 'paketo-buildpacks/npm-install:modules'
Adding layer 'paketo-buildpacks/npm-install:npm-cache'
Adding layer 'paketo-buildpacks/php-dist:php'
Adding layer 'paketo-buildpacks/php-composer:php-composer-packages'
Adding layer 'paketo-buildpacks/php-web:php-web'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving ghcr.io/making/hello-laravel...
*** Images (2edef2f24d3d):
      ghcr.io/making/hello-laravel
Reusing cache layer 'paketo-buildpacks/node-engine:node'
Reusing cache layer 'paketo-buildpacks/npm-install:modules'
Adding cache layer 'paketo-buildpacks/npm-install:npm-cache'
Reusing cache layer 'paketo-buildpacks/node-module-bom:cyclonedx-node-module'
Reusing cache layer 'paketo-buildpacks/php-dist:php'
Reusing cache layer 'paketo-buildpacks/php-composer:be95557cc36eeb82da0f4340a469bad56b57f742d2891892dcb2f8b0179790ec'
Reusing cache layer 'paketo-buildpacks/php-composer:php-composer-cache'
Successfully built image ghcr.io/making/hello-laravel

実行します。

docker run --rm -e PORT=8080 -p 8080:8080 ghcr.io/making/hello-laravel 

アクセスします。

image

Call to undefined function Illuminate\Encryption\openssl_cipher_iv_length()

というエラーが出ました。opensslモジュールがロードされていないようです。

extension.ini ファイルを作成します。

mkdir hello-laravel/.php.ini.d
cat <<EOF > hello-laravel/.php.ini.d/extension.ini 
extension=openssl.so
EOF

関連issueがあるので、将来的にはこの設定は不要になるかもしれません。
https://github.com/paketo-buildpacks/php-composer/issues/190

再度ビルドします。

pack build ghcr.io/making/hello-laravel --builder paketobuildpacks/builder:full --path hello-laravel --buildpack paketo-buildpacks/nodejs --buildpack paketo-buildpacks/php

実行します。

docker run --rm -e PORT=8080 -p 8080:8080 ghcr.io/making/hello-laravel 

アクセスすると、今度は次のエラーが出力されます。

[Sat Sep  4 17:05:32 2021] PHP Warning:  include(/layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/composer/../../app/Http/Kernel.php): failed to open stream: No such file or directory in /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/composer/ClassLoader.php on line 480
[Sat Sep  4 17:05:32 2021] PHP Warning:  include(): Failed opening '/layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/composer/../../app/Http/Kernel.php' for inclusion (include_path='/layers/paketo-buildpacks_php-dist/php/lib/php:/workspace/lib') in /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/composer/ClassLoader.php on line 480
[Sat Sep  4 17:05:32 2021] PHP Fatal error:  Uncaught ReflectionException: Class App\Http\Kernel does not exist in /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php:873
Stack trace:
#0 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php(873): ReflectionClass->__construct('App\\Http\\Kernel')
#1 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php(754): Illuminate\Container\Container->build('App\\Http\\Kernel')
#2 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(841): Illuminate\Container\Container->resolve('App\\Http\\Kernel', Array, false)
#3 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php(294): Illuminate\Foundation\Application->resolve('App\\Http\\Kernel', Array, false)
#4 /layers/ in /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 875
[Sat Sep  4 17:05:32 2021] 172.17.0.1:64658 [500]: / - Uncaught ReflectionException: Class App\Http\Kernel does not exist in /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php:873
Stack trace:
#0 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php(873): ReflectionClass->__construct('App\\Http\\Kernel')
#1 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php(754): Illuminate\Container\Container->build('App\\Http\\Kernel')
#2 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(841): Illuminate\Container\Container->resolve('App\\Http\\Kernel', Array, false)
#3 /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php(294): Illuminate\Foundation\Application->resolve('App\\Http\\Kernel', Array, false)
#4 /layers/ in /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 875

https://github.com/paketo-buildpacks/php/issues/366 を見ると、コンテナイメージ内のフォルダ構造上、シンボリックリンクを作成しないといけないようです。

cat <<EOF > hello-laravel/.profile 
#!/bin/bash
ln -s /workspace/app /layers/paketo-buildpacks_php-composer/php-composer-packages/app
EOF

再度ビルドします。

pack build ghcr.io/making/hello-laravel --builder paketobuildpacks/builder:full --path hello-laravel --buildpack paketo-buildpacks/nodejs --buildpack paketo-buildpacks/php

実行します。

docker run --rm -e PORT=8080 -p 8080:8080 ghcr.io/making/hello-laravel 

アクセスします。

image

今度はアクセスできました。


PHPのことは詳しくないですが、Cloud Native Buildpacksを使ってソースコードからコンテナイメージが作成できました。
PHPやNginx, Apache HTTP Serverの設定やバージョンアップをBuildpack側に任せられて楽です。

Found a mistake? Update the entry.
Share this article: