Oracle Database 12c を macOS 上の Docker で構築する

## 概要

- macOS に開発や検証に使用できる Oracle Database 12c を構築する
- Oracle 公式の Docker イメージとコンテナを macOS 上で作成する
- macOS に SQL*Plus Instant Client をインストールし使用する
- macOS 上の Java プログラムから Oracle Database のデータを操作する

## 今回の環境

- macOS Catalina 10.15
- Docker Desktop 2.3.0.3 (Docker version 19.03.8)
- Oracle Database 12c Release 2 (12.2.0.1.0) Enterprise Edition

## ファイルのダウンロードについて

今回の構築作業では Oracle Technology Network (OTN) からファイルをダウンロードすることが何回か発生する。ファイルをダウンロードする際には Oracle.comプロファイルのアカウントが必要になる。

[Oracle\.comプロファイルについて \| Oracle 日本](https://www.oracle.com/jp/corporate/contact/contact-accounthelp-078887-ja.html)

> Oracle.comプロファイル(MyProfile)は、オラクルの各種オンラインリソースを通じてコンテンツ、サービス、アプリケーションを利用できる、サインオン プロファイルです。

[Trials and Downloads \| Oracle 日本](https://www.oracle.com/jp/downloads/)

> すべてのソフトウェアは無償でダウンロードできます。ほとんどのソフトウェアには開発者ライセンスが付属しており、開発および試作か自己学習が目的の場合に限り、完全版の製品を無償で使用できます。

[OTNライセンスの利用可能な用途目的を教えてください。](https://faq.oracle.co.jp/app/answers/detail/a_id/4929/kw/OTN)

> お客様のアプリケーションの開発、お客様のアプリケーションのテスト、お客様のアプリケーションのプロトタイプ作成、及びお客様のアプリケーションのデモンストレーションのみを目的として（かつ、お客様のアプリケーションが、データ処理、業務、商用又は本番利用を目的として使用されたことがない場合に限られます）、プログラムを内部的にご使用いただけます。

## Docker イメージを作成

Docker イメージとコンテナの作成方法は [docker\-images/README\.md at master · oracle/docker\-images · GitHub](https://github.com/oracle/docker-images/blob/master/OracleDatabase/SingleInstance/README.md) に載っているのでそれに従う。

Docker イメージを作成するための Git リポジトリをダウンロードする。

```
$ git clone https://github.com/oracle/docker-images
```

[Oracle Database 12c Release 2 for Linux x86\-64 Downloads](https://www.oracle.com/database/technologies/oracle12c-linux-12201-downloads.html) から linuxx64_12201_database.zip をダウンロードする。

ダウンロードした linuxx64_12201_database.zip を docker-images/OracleDatabase/SingleInstance/dockerfiles/12.2.0.1 に置く。

```
$ cp ~/Downloads/linuxx64_12201_database.zip docker-images/OracleDatabase/SingleInstance/dockerfiles/12.2.0.1
```

buildDockerImage.sh を実行して Docker イメージを作成する。
-v でビルドするバージョン 12.2.0.1 を指定。
-e で Enterprise Edition を指定。
-i で MD5 チェックサムを無視する。

```
$ cd docker-images/OracleDatabase/SingleInstance/dockerfiles

$ ./buildDockerImage.sh -v 12.2.0.1 -e -i
```

Docker イメージができていることを docker images コマンドで確認できる。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
oracle/database     12.2.0.1-ee         69f1fec15f95        4 minutes ago       5.98GB
oraclelinux         7-slim              7442ca158991        4 weeks ago         120MB
```

## Docker コンテナを作成

任意の SID、PDB名、SYS・SYSTEM・PDB_ADMIN ユーザーのパスワードを指定して Docker コンテナを作成・起動する。各種パラメータを指定しない場合はそれぞれのデフォルト値が設定される。

今回は以下の値を設定した。

- SID(システム識別子): FOOSID
- PDB(プラガブル・データベース)の名前: FOOPDB
- SYS・SYSTEM・PDB_ADMIN ユーザーのパスワード: fooPassw0rd
- データベース作成時に使われるキャラクタ・セット: AL32UTF8

Docker コンテナ名も任意のものを指定できる。今回は foo_oracle とした。

```
$ docker run --name foo_oracle \
-p 1521:1521 -p 5500:5500 \
-e ORACLE_SID=FOOSID \
-e ORACLE_PDB=FOOPDB \
-e ORACLE_PWD=fooPassw0rd \
-e ORACLE_CHARACTERSET=AL32UTF8 \
-v /opt/oracle/oradata \
oracle/database:12.2.0.1-ee
```

以下のように表示されたらデータベースの用意ができている。

```
#########################
DATABASE IS READY TO USE!
#########################
The following output is now a tail of the alert.log:
Completed: alter pluggable database FOOPDB open
2020-07-16T21:25:46.847937+00:00
FOOPDB(3):CREATE SMALLFILE TABLESPACE "USERS" LOGGING  DATAFILE  '/opt/oracle/oradata/FOOSID/FOOPDB/users01.dbf' SIZE 5M REUSE AUTOEXTEND ON NEXT  1280K MAXSIZE UNLIMITED  EXTENT MANAGEMENT LOCAL  SEGMENT SPACE MANAGEMENT  AUTO
FOOPDB(3):Completed: CREATE SMALLFILE TABLESPACE "USERS" LOGGING  DATAFILE  '/opt/oracle/oradata/FOOSID/FOOPDB/users01.dbf' SIZE 5M REUSE AUTOEXTEND ON NEXT  1280K MAXSIZE UNLIMITED  EXTENT MANAGEMENT LOCAL  SEGMENT SPACE MANAGEMENT  AUTO
FOOPDB(3):ALTER DATABASE DEFAULT TABLESPACE "USERS"
FOOPDB(3):Completed: ALTER DATABASE DEFAULT TABLESPACE "USERS"
2020-07-16T21:25:49.460864+00:00
ALTER SYSTEM SET control_files='/opt/oracle/oradata/FOOSID/control01.ctl' SCOPE=SPFILE;
   ALTER PLUGGABLE DATABASE FOOPDB SAVE STATE
Completed:    ALTER PLUGGABLE DATABASE FOOPDB SAVE STATE
```

Ctrl-c を入力すると Docker コンテナが終了してしまうので注意 (コンテナは作成済みなので終了後にまた起動しても良い)。CTRL-p CTRL-q などでデタッチするのはOK。

他のターミナル等から docker ps コマンドでコンテナの作成・起動を確認できる。

```
$ docker ps -a
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS                       PORTS                                            NAMES
a1ab3d09f11b        oracle/database:12.2.0.1-ee   "/bin/sh -c 'exec $O…"   About an hour ago   Up About an hour (healthy)   0.0.0.0:1521->1521/tcp, 0.0.0.0:5500->5500/tcp   foo_oracle
```

## Docker コンテナの停止・起動

作成した Docker コンテナ foo_oracle は以下のように docker stop コマンドで停止できる。

```
$ docker stop foo_oracle
```

docker start コマンドで Docker コンテナを起動できる。

```
$ docker start foo_oracle
```

起動時の状況を確認したい場合は、docker logs コマンドで Docker コンテナのログを閲覧することができる。

```
$ docker logs -f foo_oracle
```

## Docker コンテナにログイン

起動している Docker コンテナにログインして OS や SQL*Plus を確認。

```
$ docker exec -it foo_oracle /bin/bash

[oracle@a1ab3d09f11b ~]$ uname -a
Linux a1ab3d09f11b 4.19.76-linuxkit #1 SMP Tue May 26 11:42:35 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

[oracle@a1ab3d09f11b ~]$ cat /etc/os-release 
NAME="Oracle Linux Server"
VERSION="7.8"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="7.8"
PRETTY_NAME="Oracle Linux Server 7.8"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:7:8:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 7"
ORACLE_BUGZILLA_PRODUCT_VERSION=7.8
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=7.8

[oracle@a1ab3d09f11b ~]$ sqlplus -V

SQL*Plus: Release 12.2.0.1.0 Production

[oracle@a1ab3d09f11b ~]$ exit
exit
```

## macOS に SQL*Plus Instant Client をインストール

[Instant Client for macOS \(Intel x86\) \| Oracle 日本](https://www.oracle.com/jp/database/technologies/instant-client/macos-intel-x86-downloads.html) から Version 12.2.0.1.0 (64-bit) Updated 15-Jan-2018 の以下2つのファイルをダウンロードする。

- Basic Package (instantclient-basic-macos.x64-12.2.0.1.0-2.zip)
- SQL*Plus Package (instantclient-sqlplus-macos.x64-12.2.0.1.0-2.zip)

任意の場所にインストールすることが可能なので、今回は /opt/oracle/instantclient_12_2 にインストールする。

ダウンロードした2つの ZIP ファイルを展開して中身のファイルをそのディレクトリ内に置く。

以下は、コマンドで ZIP ファイルを展開してファイルを配置する例。

```
$ sudo mkdir -p /opt/oracle/instantclient_12_2

$ sudo chown foo:wheel /opt/oracle/instantclient_12_2

$ unzip -d /opt/oracle/instantclient_12_2 -j ~/Downloads/instantclient-basic-macos.x64-12.2.0.1.0-2.zip
Archive:  /Users/foo/Downloads/instantclient-basic-macos.x64-12.2.0.1.0-2.zip
  inflating: /opt/oracle/instantclient_12_2/BASIC_README  
  inflating: /opt/oracle/instantclient_12_2/adrci  
  inflating: /opt/oracle/instantclient_12_2/genezi  
    linking: /opt/oracle/instantclient_12_2/libclntsh.dylib  -> libclntsh.dylib.12.1 
  inflating: /opt/oracle/instantclient_12_2/libclntsh.dylib.12.1  
  inflating: /opt/oracle/instantclient_12_2/libclntshcore.dylib.12.1  
  inflating: /opt/oracle/instantclient_12_2/libnnz12.dylib  
    linking: /opt/oracle/instantclient_12_2/libocci.dylib  -> libocci.dylib.12.1 
  inflating: /opt/oracle/instantclient_12_2/libocci.dylib.12.1  
  inflating: /opt/oracle/instantclient_12_2/libociei.dylib  
  inflating: /opt/oracle/instantclient_12_2/libocijdbc12.dylib  
  inflating: /opt/oracle/instantclient_12_2/libons.dylib  
  inflating: /opt/oracle/instantclient_12_2/liboramysql12.dylib  
  inflating: /opt/oracle/instantclient_12_2/ojdbc8.jar  
  inflating: /opt/oracle/instantclient_12_2/uidrvci  
  inflating: /opt/oracle/instantclient_12_2/xstreams.jar  
finishing deferred symbolic links:
  /opt/oracle/instantclient_12_2/libclntsh.dylib -> libclntsh.dylib.12.1
  /opt/oracle/instantclient_12_2/libocci.dylib -> libocci.dylib.12.1

$ unzip -d /opt/oracle/instantclient_12_2 -j ~/Downloads/instantclient-sqlplus-macos.x64-12.2.0.1.0-2.zip
Archive:  /Users/foo/Downloads/instantclient-sqlplus-macos.x64-12.2.0.1.0-2.zip
  inflating: /opt/oracle/instantclient_12_2/SQLPLUS_README  
  inflating: /opt/oracle/instantclient_12_2/glogin.sql  
  inflating: /opt/oracle/instantclient_12_2/libsqlplus.dylib  
  inflating: /opt/oracle/instantclient_12_2/libsqlplusic.dylib  
  inflating: /opt/oracle/instantclient_12_2/sqlplus  

$ ls -la /opt/oracle/instantclient_12_2
total 470816
drwxr-xr-x  23 foo   wheel        736  7 15 20:14 .
drwxr-xr-x   3 root  wheel         96  7 15 20:12 ..
-rw-rw-rw-@  1 foo   wheel        400  1 10  2018 BASIC_README
-rw-rw-rw-@  1 foo   wheel        404  1 10  2018 SQLPLUS_README
-rwxrwxrwx@  1 foo   wheel      10036  1 10  2018 adrci
-rwxrwxrwx@  1 foo   wheel      40360  1 10  2018 genezi
-r-xr-xr-x@  1 foo   wheel        342  4 25  2015 glogin.sql
lrwxrwxrwx   1 foo   wheel         20  7 15 20:14 libclntsh.dylib -> libclntsh.dylib.12.1
-rwxrwxrwx@  1 foo   wheel   85621532  1 10  2018 libclntsh.dylib.12.1
-rwxrwxrwx@  1 foo   wheel    4685408  1 10  2018 libclntshcore.dylib.12.1
-r-xr-xr-x@  1 foo   wheel    8179072  6 29  2017 libnnz12.dylib
lrwxrwxrwx   1 foo   wheel         18  7 15 20:14 libocci.dylib -> libocci.dylib.12.1
-rwxrwxrwx@  1 foo   wheel    1465312  1 10  2018 libocci.dylib.12.1
-rwxrwxrwx@  1 foo   wheel  124769196  1 10  2018 libociei.dylib
-r-xr-xr-x@  1 foo   wheel     151748  8  8  2017 libocijdbc12.dylib
-r-xr-xr-x@  1 foo   wheel     237780  1  8  2018 libons.dylib
-rwxrwxrwx@  1 foo   wheel      84988  1 10  2018 liboramysql12.dylib
-rwxrwxrwx@  1 foo   wheel    1267088  1 10  2018 libsqlplus.dylib
-r-xr-xr-x@  1 foo   wheel    1639388  7 12  2017 libsqlplusic.dylib
-r--r--r--@  1 foo   wheel    4036257 12 14  2016 ojdbc8.jar
-rwxr-xr-x@  1 foo   wheel       8480  1 10  2018 sqlplus
-rwxrwxrwx@  1 foo   wheel     146084  1 10  2018 uidrvci
-r--r--r--@  1 foo   wheel      74230  1 26  2017 xstreams.jar
```

起動用に環境変数を設定する。
NLS_LANG を設定していないと日本語を適切に処理できずに文字化けが発生する。

```
$ export ORACLE_HOME=/opt/oracle/instantclient_12_2
$ export PATH=/opt/oracle/instantclient_12_2:$PATH
$ export NLS_LANG=Japanese_Japan.AL32UTF8
```

splplus コマンドでバージョンを確認。

```
$ sqlplus -V

SQL*Plus: Release 12.2.0.1.0 Production
```

起動時に各種ファイルについて「開発元を検証できないため開けません。」と表示された場合はシステム環境設定を起動 (open /System/Applications/System\ Preferences.app) して、「セキュリティとプライバシー」の「一般」からそのファイルを許可する必要がある。

## ユーザーを作成

SYSTEM ユーザーで sqlplus を起動してデータベースに接続。
新しいユーザー foo_user を作成して以下の権限・ロールを付与する。

- create session: Oracle Database への接続権限
- resource: オブジェクト操作権限を持つロール
- unlimited tablespace 表領域の無制限な使用権限

```
$ sqlplus system@\"localhost:1521/foosid\"

SQL*Plus: Release 12.2.0.1.0 Production on 金 7月 17 21:04:55 2020

Copyright (c) 1982, 2017, Oracle.  All rights reserved.

パスワードを入力してください: 


Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
に接続されました。

SQL> alter session set container = foopdb;

セッションが変更されました。

SQL> show con_name;

CON_NAME
------------------------------
FOOPDB

SQL> create user foo_user identified by fooPassw0rd;

ユーザーが作成されました。

SQL> grant create session to foo_user;

権限付与が成功しました。

SQL> grant resource to foo_user;

権限付与が成功しました。

SQL> grant unlimited tablespace to foo_user;

権限付与が成功しました。

SQL> select grantee, privilege from dba_sys_privs where grantee = 'FOO_USER';

GRANTEE  PRIVILEGE
-------- ----------------------------------------
FOO_USER UNLIMITED TABLESPACE
FOO_USER CREATE SESSION

SQL> exit
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Productionとの接続が切断されました。
```

## テーブルを作成

foo_user ユーザーで sqlplus を起動してデータベースに接続。
テーブルを作成してレコードを追加する。

```
$ sqlplus foo_user@\"localhost:1521/foopdb\"

SQL*Plus: Release 12.2.0.1.0 Production on 金 7月 17 21:07:23 2020

Copyright (c) 1982, 2017, Oracle.  All rights reserved.

パスワードを入力してください: 


Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
に接続されました。

SQL> create table foo_table (id number(8) not null, name varchar2(16 char) not null);

表が作成されました。

SQL> select table_name from user_tables;

TABLE_NAME
--------------------------------------------------------------------------------
FOO_TABLE

SQL> desc foo_table
 名前                                    NULL?    型
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER(8)
 NAME                                      NOT NULL VARCHAR2(16 CHAR)

SQL> insert into foo_table values(1, 'Alice');

1行が作成されました。

SQL> insert into foo_table values(2, 'ボブ');

1行が作成されました。

SQL> select * from foo_table;

        ID NAME
---------- ----------------------------------------------------------------
         1 Alice
         2 ボブ

SQL> exit
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Productionとの接続が切断されました。
```

## macOS 上の Java プログラムから接続

JDBC Driver を [12\.2\.0\.1 \- JDBC and UCP Download Page](https://www.oracle.com/database/technologies/jdbc-ucp-122-downloads.html) などからダウンロードして入手する。

今回は ojdbc8.jar を使用する。

```
$ java -jar ojdbc8.jar
Oracle 12.2.0.1.0 JDBC 4.2 compiled with javac 1.8.0_91 on Tue_Dec_13_06:08:31_PST_2016
#Default Connection Properties Resource
#Fri Jul 17 21:46:20 JST 2020

***** JCE UNLIMITED STRENGTH IS INSTALLED ****
```

以下の内容を JdbcSample.java というファイル名で保存する。

```java
import java.sql.*;

class JdbcSample {
  public static void main (String args []) throws Exception {
    String url = "jdbc:oracle:thin:@//localhost:1521/foopdb";
    String user = "foo_user";
    String password = "fooPassw0rd";
    Connection con = DriverManager.getConnection(url, user, password);
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery("select id, name from foo_table");
    while (rs.next()) {
      System.out.println("id=" + rs.getInt("id") + ", name=" + rs.getString("name"));
    }
    stmt.close();
    con.close();
  }
}
```

ソースコードをコンパイルする。
今回は Java 8 (AdoptOpenJDK 1.8.0_252-b09) を使用する。

```
$ javac JdbcSample.java
```

実行する。Oracle Database からデータを取得しているのを確認できる。

```
$ java -classpath .:ojdbc8.jar JdbcSample
id=1, name=Alice
id=2, name=ボブ
```

## 参考資料

### Oracle Database

- [Oracle Database 12cリリース2 \- スタート・ガイド](https://docs.oracle.com/cd/E82638_01/)
- [Oracle Database 2日でデータベース管理者 12c リリース2 \(12\.2\)](https://docs.oracle.com/cd/E82638_01/admqs/)
- [Oracle Database SQL言語リファレンス, 12cリリース2 \(12\.2\)](https://docs.oracle.com/cd/E82638_01/sqlrf/)
- [Oracle Database ソフトウェア・ダウンロード \| Oracle Technology Network \| Oracle 日本](https://www.oracle.com/jp/database/technologies/oracle-database-software-downloads.html)

### Oracleシステム識別子 (SID)

[Oracleデータベース・インスタンス](https://docs.oracle.com/cd/E82638_01/cncpt/oracle-database-instance.html#GUID-8BB8140D-63ED-454E-AAC3-1964F80D102D)

> Oracleシステム識別子(SID)
> システム識別子(SID)とは、特定のホスト上でOracleデータベース・インスタンスを示す一意の名前です。

### Pluggable Database (PDB)

[Oracle DB engineer direct report \| Oracle 日本](https://www.oracle.com/jp/technical-resources/articles/jissenn12c.html)

> Oracleを含む従来のデータベース管理システムは、SQLの実行やトランザクションを管理するシステム部分と、いわゆるデータベースの部分がほぼ不可分でした。マルチテナント・アーキテクチャでは、CDBと呼ばれる部分がデータベース管理システム、PDBと呼ばれる部分が論理的なデータベースと言えます。
> 
> PDBはCDBにプラグすることで利用可能になります。PDBはユーザーやアプリケーションからは従来の（マルチテナント・アーキテクチャが採用されていない）データベースと同様に扱うことができます。CDBには複数のPDBをプラグすることができ、その結果、既存のスキーマやアプリケーションを変更することなく複数のデータベース環境を統合することが可能です。

### Oracle Database on Docker

- [GitHub \- oracle/docker\-images: Official source for Docker configurations, images, and examples of Dockerfiles for Oracle products and projects](https://github.com/oracle/docker-images/)
- [docker\-images/README\.md at master · oracle/docker\-images · GitHub](https://github.com/oracle/docker-images/blob/master/OracleDatabase/SingleInstance/README.md)

### SQL*Plus Instant Client

[SQL\*Plusのクイック・スタート](https://docs.oracle.com/cd/E82638_01/sqpug/SQL-Plus-quick-start.html#GUID-2AA5AAC7-6027-4B2F-8442-C1EA79D9956B)

> SQL*Plusは、Oracle Databaseのインストール時にインストールされる対話型のバッチ問合せツールです。コマンドライン・ユーザー・インタフェースがあります。

[SQL\*Plus Instant Client](https://docs.oracle.com/cd/E82638_01/sqpug/SQL-Plus-instant-client.html#GUID-9DC272F8-0805-4582-87C6-67B2BC816A2C)

> SQL*Plus Instant Clientは、SQL*Plusのコマンドラインのすべての機能を備えたスタンドアロン製品です。既存のRemote Oracle Databaseに接続しますが、独自のデータベースはありません。簡単にインストールでき、SQL*Plusコマンドラインの使用に必要なOracle Database Clientの完全なインストールと比較すると、非常に少ないディスク領域を使用します。

- [SQL\*Plusユーザーズ・ガイドおよびリファレンス, リリース2 \(12\.2\)](https://docs.oracle.com/cd/E82638_01/sqpug/)
- [Oracle Instant Client \- Free tools and libraries for connecting to Oracle Database \| Oracle 日本](https://www.oracle.com/jp/database/technologies/instant-client.html)
- [Instant Client for macOS \(Intel x86\) \| Oracle 日本](https://www.oracle.com/jp/database/technologies/instant-client/macos-intel-x86-downloads.html)

### JDBC

- [JDBCドライバ \| Oracle 日本](https://www.oracle.com/jp/database/technologies/appdev/jdbc.html)
- [Oracle Database JDBC開発者ガイド, 12cリリース2 \(12\.2\)](https://docs.oracle.com/cd/E82638_01/jjdbc/)