DockerでMacにOracle 19cをインストールして開発環境を構築する

# MacでOracle 19cの開発環境を構築したい

MacにはOracleが直接インストールできないのでDockerをつかってOracleをインストールして開発環境を構築したいと思います！
せっかくだから最新の19cで！

## 下準備

必要なツールは下記のものです。
ググればたくさんでてきますので、インストールしておいてください！

- git
- Docker

後述しますが、それに加えて別途Oracle本体のダウンロードが必要になります。
ダウンロードにはOracleの技術者ネットワークであるOTNへの登録が必要です（無料）

*Docker + Mac + Oracle* のとてつもなく親切な記事がすでにあるのでそちらも参考にしてください。

[Oracle on docker for Mac](https://qiita.com/daiki_hirano/items/e331a0017250c75e7a07)
[macOSでOracle Database使いたい](https://qiita.com/yuttoku/items/f9aa9c3caf17d95c81b7)

ってかこの記事の存在意義 is 何？

# 手順の概要

環境構築のながれは下記です！

1. OracleのDockerイメージの作成
2. Dockerイメージからコンテナの作成

簡単だね！

ではやっていきましょう！

## gitでOracle公式のDockerFileをクローン

まずはじめにDockerのImageを作るために、Oracleが提供してくれているDockerFileを入手します！
ターミナルで適当なディレクトリに移動して下記のコマンドを実行します。

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

余裕があるかたは下記のパスにあるreadmeには目を通しましょう。
公式ドキュメントに目を通すの大事！


`docker-images/OracleDatabase/SingleInstance/README.md`


## Oracleをダウンロード

DockerFileにはOracleをインストールためのバイナリが含まれていませんので、Oracleのサイトよりバイナリをダウンロードしてきます。ダウンロードにはOTNへの登録が必要です。

[OTN (Oracle Technology Network)](https://www.oracle.com/technetwork/jp/index.html)

[OracleDatabaseのダウンロード](https://www.oracle.com/technetwork/jp/database/enterprise-edition/downloads/index.html)

今回はOracle19cをいれようと思うので19.3.0をダウンロードします。

プラットフォームにあわせて色々なバージョンがありますが **Linux x86-64** ですよ！


ダウンロードしたファイルを下記のパスにzipのままおきます。

`docker-images/OracleDatabase/SingleInstance/dockerfiles/19.3.0/LINUX.X64_193000_db_home.zip`


## Dockerのイメージを作成

準備は整いましたのでDockerのイメージを作成していきます！

いろんなものを作れるみたいですが、今回は開発用にデータベースのシングルインスタンスを作るので下記のパスに移動します！

`docker-images/OracleDatabase/SingleInstance/dockerfiles`

移動したら下記のコマンドを実行します。


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

このコマンドではEnterpriseEdition (EE) が作られます。Standartd Editionのイメージを作りたい方は **-e** ではなく **-s** を指定します。よくわからなければそのままで。

オプションの意味が知りたい人や余裕がある人は、OracleDatabaseのImage作成からコンテナ作成までのことが書いてあるReadmeがあるのでそれにも目を通しておきましょう！

`docker-images/OracleDatabase/SingleInstance/README.md`

公式ドキュメント大事！

## Dockerのイメージがちゃんとできたか確認

それではDockerのImageが作成されたはずなので確認してみましょう！

```
$ docker images
```

とコマンドを打つと

```
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
oracle/database     19.3.0-ee           92145214b3d8        5 days ago          6.65GB
oraclelinux         7-slim              874477adb545        5 days ago         118MB
```

こんな感じででてくればOKですね！
少し前までは **oraclelinux** は出来ませんでしたがDatabaseイメージで使うようになったみたいですね！

## DockerのImageからDockerのコンテナを作成

それではいよいよコンテナを作成します！

README.mdを読んで適宜オプションをつけます。
「オプションを書かないとDefault値がはいる」みたいなこと書いてありますが何も入らずにインストールに失敗したことがあったので全部明示的に指定した方がいいと思います。
（昔やったときは何も書かずにいけたと思ったんですが。。。）

```
# コマンドの書き方
$ docker run --name <コンテナ名> -p <自分のOracle用ポート>:<dockerのポート(1521固定)> -p <自分のEM用ポート>:<dockerのポート(5500固定)> -e ORACLE_SID=<OracleのSID> -e ORACLE_PDB=<作成されるPDBのSID> -e ORACLE_PWD=<systemユーザーとかのパスワード> -e ORACLE_CHARACTERSET=<DBのキャラクタセット>  oracle/database:19.3.0-ee

# 具体例
# ※データベースユーザーのパスワードにあたるmypasswordの部分はもちろん書き換えてくださいね！
$ docker run --name orcl -p 1521:1521 -p 5500:5500 -e ORACLE_SID=orclcdb -e ORACLE_PDB=orclpdb1 -e ORACLE_PWD=mypassword -e ORACLE_CHARACTERSET=AL32UTF8  oracle/database:19.3.0-ee
```

各変数の説明は以下の通りです。

- **コンテナ名**
 - dockerでのコンテナ名。なんでもいいです。docker psなどを打った時にでます。
- **自分のOracle用ポート**
 - OracleDatabaseに接続するための元ポート。よくわからなければ**1521**で大丈夫。コンテナを二つ以上作成する場合は**1522**などずらしましょう！
- **自分のEM用ポート**
 - EnterpriseManagerに接続するためのポート。よくわからなければ**5500**で大丈夫。EMを使わなければ指定しなくても大丈夫。コンテナを二つ以上作成する場合は**5502**などずらしましょう！
- **ORACLE_SID**
 - SID。Oracleの識別IDみたいなもの。default値はORCLCDB。別になんでもいい。
- **ORACLE_PDB**
 - 12c以降はプラガブルDBなので、作成されるPDBのSID。default値はORCLPDB1。別になんでもいい。
- **ORACLE_PWD**
 - system, sys, pdbのsystemなどのパスワード。指定しないとランダムに作成されてログの上の方にでます。


初回だけ作り終わったあともshellが起動しっぱなしになります。（READMEにも書いてある）
別に害はないですが、気になる場合は `control + C` で終了させてから `docker start <コンテナ名>` で起動しましょう。その際、次に止める場合は `docker stop <コンテナ名>` です。

#### 成功時

下記のような部分が画面の出力中にあらわれます。

```
#########################
DATABASE IS READY TO USE!
#########################
```

やったー :raised_hands: :raised_hands: :raised_hands:

早速接続確認をしてみましょう！

#### 失敗時

下記のような部分が画面の出力中に無慈悲な感じで出ます。

```
#####################################
########### E R R O R ###############
DATABASE SETUP WAS NOT SUCCESSFUL!
Please check output for further info!
########### E R R O R ###############
#####################################
```

なんだとー :sob: :sob: :sob:

また、コンテナが正常に作成された場合でも接続してみるとDatabaseがうまく構築できてない場合があったりします。
Oracleって感じがしますね！

失敗した時は失敗したコンテナを削除し、設定を見直してもう一度トライしてみましょう！

```
# コンテナを全部表示
$ docker ps -a
```

```
# 失敗したコンテナを削除
$ docker rm <失敗したコンテナ名>
# 具体例
$ docker rm orcl
```

Oracleのコンテナを作成するとVolumeが自動的に作成されるみたいです。
失敗コンテナを削除するだけではVolumeが残りますので適宜削除してください。
ほっておくと容量を圧迫するのでエラーがおきるようになります。対処方法は後述します。

### 失敗したときのチェックリスト

##### 出来たっぽいけど接続してみると何かがおかしい
昔は大丈夫だった気がしますが、ORACLEのSIDを明示的に指定しないと失敗することがあります。（失敗しました）

Oracleを初めて触るとかだとなんで出来てるっぽいのになんでダメなのか探すのが難しいと思いますので、とりあえず全部オプションを指定してやり直してみてください。

それでもダメな場合は近くの詳しい人に聞きましょう！

##### 何度も失敗しているうちに「ディスク容量がない」系のエラーが出るようになった

何度か失敗していると下記みたいなエラーログで死ぬ場合があります。

```
[FATAL] [DBT-06604] The location specified for 'Data Files Location' has insufficient free space. 
```

Oracleのインストールプログラムがディスク容量がたりないよ！って言ってます。

Dockerにそれほど詳しい訳ではないのでよくはわからないんですが、Dockerの容量制限に当たってるみたいです。
Oracleのコンテナを作成する際にDockerのVolumeが作成されるらしく、失敗したコンテナを削除するだけではVolumeは削除されません。残ってしまいます。

```
# ボリュームの確認
$ docker volumes
```

おそらく作った覚えのないvolumeが出来てると思います。
コンテナに紐づいてないvolumeを削除するコマンドがあるのでそれを実行します。（失敗したコンテナを削除してから実行してください）
別途保存しているvolumeなどがある場合は適宜調査して一つずつ消してくださいね！

```
# コンテナに紐づいてないvolumeを削除する
$ docker volume prune
```

### DB作成のヴァリエーション
#### 別なキャラクタセットでDBを作成するサンプル
時に顧客のDBがSJISだったりして移行すると文字化けするなどの悲劇が発生し、SJISのDBが必要になる場合があります。
幸い超簡単にDBのキャラクタセットを変更することが可能です！やった！

ただオプションを変えるだけですが一応サンプル載せときます。

#### SJISチルダで作る時のサンプル

```
$ docker run  --name orclsjis -p 1521:1521 -p 5500:5500 -e ORACLE_SID=orclcdb -e ORACLE_PDB=orclpdb1 -e ORACLE_PWD=mypassword -e ORACLE_CHARACTERSET=JA16SJISTILDE  oracle/database:19.3.0-ee
```

`-e ORACLE_CHARACTERSET=JA16SJISTILDE` の部分で環境変数にSJISのキャラクタセットをセットするだけですね！ `JA16SJIS` ではなく `JA16SJISTILDE` になってるのはチルダ（~）が `JA16SJIS` では文字化けするので文字化けしないバージョンのキャラクタセットにしているというだけです。要件にあった方でやってください。


## 接続確認

さあコンテナはできたはずです！
ちゃんとできたか確認していきましょう！

ご自分のMacにSqlPlusインスタントクライアントが入っている場合は下記で繋がります。

```
＄ sqlplus system/<パスワード>@localhost:<自分のOracle用ポート>/<ORACLE_SID>

# 具体例
$ sqlplus system/mypassword@localhost:1521/orclcdb
```

SQLDeveloperなどで繋げる場合は普通に指定すれば大丈夫です。

インストール作業は一応ここまでです！

おつかれさまでした :beer: :beer: :beer:

# 開発で楽チンなように調整

ここからはOracleの設定なので必須ではないです。

## PDBにSIDで接続できるようにする

Oracleさんは12cからマルチテナント方式になりました。
まずコンテナDBに繋いでからプラガブルDBに繋ぐというステップを踏みますのでめんどくさいですね。
なの設定を変更してPDBにいきなり繋げられるように変更しましょう。

lisner.oraに下記を追記すると外からSIDのみでPDBに接続できるようになります。

```
USE_SID_AS_SERVICE_LISTENER = ON
```

dockerの中に入ります。

```
$ docker exec -it <コンテナ名> bash

# 具体例
$ docker exec -it orcl bash
```

viとかが入ってないので苦肉の策としてechoでリダイレクトして追記しちゃいます。

(バックアップを取らずに書き換えるのは **非推奨** です！DockerとローカルPCでファイルをやりとりする方法も後述してますのでそちらを参考にしてください！)

```
$ echo "USE_SID_AS_SERVICE_LISTENER = ON" >> /opt/oracle/oradata/dbconfig/<ORACLE_SID>/listener.ora

# 具体例
$ echo "USE_SID_AS_SERVICE_LISTENER = ON" >> /opt/oracle/oradata/dbconfig/ORCLCDB/listener.ora

# 似たような場所にあると思いますが実際のlisterner.oraの場所は自分で確認してください
```

リスナーを再起動します。


```
# 停止
$ lsnrctl stop

# 起動
$ lsnrctl start
```

しばらく待つとリスナーが上がってきます。
いきなり繋いでもまだリスナーが上がってないことがあるので注意しましょう。

```
# 接続確認するための接続情報
url: localhost
port: <自分のOracle用ポート>
sid: <ORACLE_PDBで指定した文字列>

# 具体例
url: localhost
port: 1521
sid: orclpdb1
```

繋がりましたでしょうか？

sqlplusからは別にこんなことしなくてもなぜかつながります。
sqldeveloperなどから繋ぐときはこれをやりましょうね！

もし追記で間違えた時は後述するファイルを置き換える方式でやり直しましょう。
ってか普通ははファイルのバックアップとってからやるよね。。。

###  java.sql.SQLException: ORA-28040: No matching authentication protocol
開発しているアプリがふるい認証方法でアクセスしてるとこのエラーが出る場合があります。
本当はアプリを直した方がいいんですが、応急処置としてOracleの設定を変えます。
その場合は下記をsqlnet.oraに追記してください。

```
SQLNET.ALLOWED_LOGON_VERSION_SERVER=11
```
11のところは適宜かきかえてください。
12cで認証方式がかわったので認証方式を11gの時のに指定しています。 パスワードの大文字小文字区別のあたりもからんでてややこしいので、詳細はORAエラーの番号で調べてください。

```
// 具体例
$ echo "SQLNET.ALLOWED_LOGON_VERSION_SERVER=11" >> /opt/oracle/oradata/dbconfig/ORCLCDB/sqlnet.ora
```

リスナーとかの再起動の必要はありません。
もしこれでもダメな場合は上記で触れたパスワードの大文字小文字区別のバージョンにひっかかってる可能性があるので、Oracleのデータベースユーザーのパスワードを再設定するとOKな場合があります。

#### Docker内のファイルをおきかえる方法

なにか間違えた時は追記方式ではだめなのでdockerからファイルをコピーしてきて、それを編集してまた戻すという方法をつかってください。
dockerのなかにコピーしたあとは権限を確認＆調整してくださいね！
sqlnet.oraは `oracle:oinstall` ですよ！

##### dockerからローカルにコピーしてくるコマンド

```
$ docker cp <コンテナ名>:/path/to/file file

# 具体例
$ docker cp orcl:/opt/oracle/oradata/dbconfig/ORCLCDB/sqlnet.ora sqlnet.ora
```

##### ローカルからdockerにコピーするコマンド

```
$ docker cp file <コンテナ名>:/path/to/file

# 具体例
$ docker cp sqlnet.ora orcl:/opt/oracle/oradata/dbconfig/ORCLCDB/sqlnet.ora
```

##### rootとしてDockerのコンテナ中にはいる

権限を変更するのにDockerのコンテナ内でrootにならないといけない場面があると思います。
ですが、rootのパスワードがわからないはずなのでsuやsudoは使えないとおもいます。
なのでコンテナにログインする際にでログインユーザーにrootを指定して入ります。

```
$ docker exec -it -u root -w / <コンテナ名> bash

# 具体例
$ docker exec -it -u root -w / orcl bash
```

`-u root` でログインユーザーをrootに指定しています。
またログイン後のデフォルトのworkdirが */home/oracle* になっていてrootユーザーに閲覧権限がなくてエラーになるので、 `-w /` でworkdirを */ (ルート)* に指定しています。

## おわり

おつかれさまでした。
ゆるふわOracleさんはうまくいったりいかなかったりして大変ですね！

なにか間違い等ありましたら教えてください！

:beer: :beer: :beer: