PHP + Oracle Instant ClientのDockerイメージ作成
PHPの公式Dockerイメージを元に、Oracle Instant Clientとoci8、pdo_ociモジュールを導入した Dockerイメージを作成してみました。


公式イメージの概要
まず以下を把握しておきます。

  • ApacheのDOCUMENT_ROOT のデフォルトは /var/www/html
  • Apacheの設定ファイルは /etc/apache2/ 以下
  • php.iniの場所は /usr/local/etc/php/php.ini
  • PHPのモジュールの内、mbstring、zlib、iconv、sqlite、pdo_sqliteは最初から入っているので、 自分で入れる必要はありません。


Dockerfile(PHP 8.5)

FROM php:8.5-apache

ENV NLS_LANG=JAPANESE_JAPAN.UTF8
ENV ORACLE_HOME=/opt/instantclient
ENV LD_LIBRARY_PATH=$ORACLE_HOME
ENV TNS_ADMIN=$ORACLE_HOME/network/admin

ARG OIC_VER_DSV=21.19.0.0.0
ARG OIC_VER_DEC=2119000
ARG OIC_VER_DIR=21_19

RUN apt-get update && apt-get install libaio1t64 libaio-dev wget unzip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/${OIC_VER_DEC}/instantclient-basic-linux.x64-${OIC_VER_DSV}dbru.zip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/${OIC_VER_DEC}/instantclient-sdk-linux.x64-${OIC_VER_DSV}dbru.zip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/${OIC_VER_DEC}/instantclient-sqlplus-linux.x64-${OIC_VER_DSV}dbru.zip && \
    mv instantclient-*.zip /opt && \
    cd /opt && \
    unzip instantclient-basic-linux.x64-${OIC_VER_DSV}dbru.zip && \
    unzip -o instantclient-sdk-linux.x64-${OIC_VER_DSV}dbru.zip && \
    unzip -o instantclient-sqlplus-linux.x64-${OIC_VER_DSV}dbru.zip && \
    rm -rf instantclient-*.zip && \
    ln -s instantclient_${OIC_VER_DIR} instantclient

# for Debian13 ni libaio.so.1 ga nai mondai
RUN cd /usr/lib/x86_64-linux-gnu && ln -s libaio.so.1t64 libaio.so.1

RUN echo $LD_LIBRARY_PATH > /etc/ld.so.conf.d/oic.conf && ldconfig

# プロキシの設定が必要ならば行う
RUN pear config-set http_proxy http://proxy.mycompany.com:8080/

RUN echo 'instantclient,/opt/instantclient/' | pecl install oci8
RUN echo 'instantclient,/opt/instantclient/' | pecl install pdo_oci

COPY ./php.ini  /usr/local/etc/php/
COPY ./html     /var/www/html
COPY ./tnsnames.ora  $TNS_ADMIN/
##COPY ./database /var/www/database
# end.

PHP8.5+OCIでは8.4にはなかった大きな注意点があります。 Debian13ベースになったことで、libaio1がlibaio1t64になった一方、 Oracle Instant Clientは相変わらず libaio.so.1 を要求するので、 名前を合わせるために無理やりリンクを張っています。


Dockerfile(PHP 8.4)

FROM php:8.4-apache

ARG OIC_VER_DSV=21.16.0.0.0
ARG OIC_VER_DEC=2116000
ARG OIC_VER_DIR=21_16

ENV NLS_LANG=JAPANESE_JAPAN.UTF8
ENV ORACLE_HOME=/opt/instantclient
ENV LD_LIBRARY_PATH=$ORACLE_HOME
ENV TNS_ADMIN=$ORACLE_HOME/network/admin

RUN apt update && apt-get install libaio1 libaio-dev wget unzip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/${OIC_VER_DEC}/instantclient-basic-linux.x64-${OIC_VER_DSV}dbru.zip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/${OIC_VER_DEC}/instantclient-sdk-linux.x64-${OIC_VER_DSV}dbru.zip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/${OIC_VER_DEC}/instantclient-sqlplus-linux.x64-${OIC_VER_DSV}dbru.zip && \
    mv instantclient-*.zip /opt && \
    cd /opt && \
    unzip instantclient-basic-linux.x64-${OIC_VER_DSV}dbru.zip && \
    unzip -o instantclient-sdk-linux.x64-${OIC_VER_DSV}dbru.zip && \
    unzip -o instantclient-sqlplus-linux.x64-${OIC_VER_DSV}dbru.zip && \
    rm -rf instantclient-*.zip && \
    ln -s instantclient_${OIC_VER_DIR} instantclient

RUN echo $LD_LIBRARY_PATH > /etc/ld.so.conf.d/oic.conf && ldconfig

##ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
##RUN chmod +x /usr/local/bin/install-php-extensions
##RUN install-php-extensions oci8 pdo_oci

# プロキシの設定が必要ならば行う
RUN pear config-set http_proxy http://proxy.mycompany.com:8080/

RUN echo 'instantclient,/opt/instantclient/' | pecl install oci8
RUN echo 'instantclient,/opt/instantclient/' | pecl install pdo_oci

COPY ./php.ini  /usr/local/etc/php/
COPY ./html     /var/www/html
COPY ./tnsnames.ora  $TNS_ADMIN/
##COPY ./database /var/www/database
# end.

Dockerfileでは変数をARGかENVで定義できます。 ARGはビルド時のみ有効、ENVは作られたコンテナイメージにも環境変数として引き継がれます。
注意点が4つあります。
  • oci8モジュールの導入にはInstant Clientのbasicとsdkは必須です。 sqlplusが必須かどうかは分かりませんが、問題の調査にあると便利そうなので入れておきます。
  • install-php-extensions ツールでPHPモジュール oci8とpdo_oci をインストールすると、 自前でOracle Instant ClientのBasicLite21.4をインストールしてしまいます。BasicLiteは日本語非対応なので使えません。 結局、Instant Clientを自分でDL/展開し、peclコマンドでインストールする必要があります。
  • Oracle Instant Clientの3つのZipファイルには同名のREADME.*というファイルがあるので、 unzip実行時に重複ファイルを強制的に上書きする-oオプションが必須です。
  • 上記の例では対象はありませんが、幾つかのPHPモジュールをインストールする際 「config.m4がないからphpizeが失敗した」というエラーになることがあります。 この現象、何度もネットで報告されていますが、中々解決しないみたいです。 その場合は、仕方ないのでコンテナの中に入って自分でソース配布を配置し、 config0.m4などのファイルをconfig.m4に改名してからphpize⇒コンパイルするしかないようです。


ビルドと動作確認

podman build -t myphp .

#フォアグラウンドで動作確認
podman run --rm -p 8090:80 --name myphp-app myphp

# ブラウザで以下にアクセスします。
http://{hostname}:8090/phpinfo.php
http://{hostname}:8090/sqlitetest.php

# 確認が終わったらCTRL+Cで終了

#バックグラウンドで動作確認
podman run --rm -d -p 8090:80 --name myphp-app myphp
# 中に入って調べる場合
podman exec -it myphp-app /bin/bash

#document_rootをホスト側から指定する場合は以下のようにする。
podman run -v /home/me/html/:/var/www/html/:Z --rm -d -p 8090:80 --name myphp-app myphp

SELinuxが有効な場合で、-vを付けてマウントしたディレクトリのファイルにアクセスすると 「403 Forbidden」が発生する場合は、-vの末尾に:zか:Zを付けます。 :zは共有型、:Zは専有型で、ホストのボリュームを複数又は単一のコンテナに特別なSELinuxラベルを付けてマウントするオプションです。


Dockerfile(PHP 8.3 古い版)

FROM php:8.3-apache

RUN apt update && apt-get install libaio1 libaio-dev wget unzip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/2111000/instantclient-basic-linux.x64-21.11.0.0.0dbru.zip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/2111000/instantclient-sdk-linux.x64-21.11.0.0.0dbru.zip && \
    wget https://download.oracle.com/otn_software/linux/instantclient/2111000/instantclient-sqlplus-linux.x64-21.11.0.0.0dbru.zip && \
    mv instantclient-*.zip /opt && \
    cd /opt && \
    unzip instantclient-basic-linux.x64-21.11.0.0.0dbru.zip && \
    unzip instantclient-sdk-linux.x64-21.11.0.0.0dbru.zip && \
    unzip instantclient-sqlplus-linux.x64-21.11.0.0.0dbru.zip && \
    rm -rf instantclient-*.zip && \
    ln -s instantclient_21_11 instantclient

ENV NLS_LANG=JAPANESE_JAPAN.UTF8
ENV ORACLE_HOME=/opt/instantclient
ENV LD_LIBRARY_PATH=$ORACLE_HOME
ENV TNS_ADMIN=$ORACLE_HOME/network/admin

RUN echo $LD_LIBRARY_PATH/ > /etc/ld.so.conf.d/oic.conf && ldconfig

##ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
##RUN chmod +x /usr/local/bin/install-php-extensions
##RUN install-php-extensions oci8 pdo_oci

# プロキシの設定が必要ならば行う
RUN pear config-set http_proxy http://proxy.mycompany.com:8080/

RUN echo 'instantclient,/opt/instantclient/' | pecl install oci8
RUN echo 'instantclient,/opt/instantclient/' | pecl install pdo_oci

COPY ./php.ini  /usr/local/etc/php/
COPY ./html     /var/www/html
COPY ./tnsnames.ora  $TNS_ADMIN/
##COPY ./database /var/www/database
# end.


php.iniのサンプル

[Date]
date.timezone = "Asia/Tokyo"

##extension=mbstring
extension=oci8
extension=pdo_oci
##extension=pdo_sqlite


サンプルプログラム(phpinfo)
上記のhtmlディレクトリの中に、phpinfo()で設定を確認するプログラムを入れておくと便利です。
内容はいつも通りなので言う事ないです。

<?php
phpinfo();


サンプルプログラム(sqlite)
Oracle接続の前にSQLite3で簡単にPDOの動作を確認するには以下のようなプログラムを置いておきます。
これをアレンジすればOracleの接続確認もできますね。

<?php
$sql = "SELECT * FROM TEST_TABLE ORDER BY 1";

try {
    // SQLiteの場合
    $pdo = new PDO("sqlite:/var/www/database/testdb", null, null);
    // Oracleの場合はこんな感じになると思います。
    $pdo = new PDO("oci:dbname=//falcon.nsnhnkmmkk.co.jp:1521/TESTDB", "testuser", "testpass");

    $stmt = $pdo->query($sql);
    print "<html lang='ja'><head><meta charset='UTF-8'></head><body>";
    while($row = $stmt->fetch()){
        print implode(", ", $row) . "<br>" . PHP_EOL;
    }
    print "</body></html>";
} catch(PDOException $e){
    var_dump($e->getMessage());
}
$pdo = null;

Misc. Topics Top

(first uploaded 2024/09/01 last updated 2026/01/23, URANO398)