これは、GoとOracle Cloud Infrastructure(OCI)に関する5つのパート・シリーズの4番目の部分です。このシリーズでは、Goアプリケーションを作成して、コンピュート・インスタンス(VM)のOracle Cloud Infrastructureで実行する方法、Kubernetesでコンテナ化する方法またはサーバーレス・ファンクションとして実行する方法について説明します。この記事では、OCI DevOpsを使用して、これらのGoアプリケーションのビルドとデプロイメントを自動化する方法を紹介しています。重要なトピックは、GoアプリケーションのOCIサービス(OCIで実行されているものと、他の場所で実行されているGoコードの両方)を使用する方法です。ここで説明するOCIサービスには、オブジェクト・ストレージ、ストリーミング、Key Vault、Autonomous Databaseなどがあります。
これらの記事をフォローするには、読者は少なくともGoアプリケーションの作成方法に関する基本的な知識を持っている必要があります。読者は、独自のGo開発環境にアクセスできるものとします。例やスクリーンショットの中には、特に開発ツールとしてVS Codeについて言及するものもあります。ただし、他のエディタやIDEも使用できます。これらの記事で示されているGoコードは、最も単純な形式で、依存関係が最小限であることを最大限にわかりやすくするために多くのメカニズムを示しています。読者は、意味のある機能や本番対応のコードを期待してはいけません。
このシリーズでは、OCIへの移行方法について説明します。この例を試すには、読者がOCIテナンシへのアクセス権を持ち、これらの記事で説明するOCIリソースを作成する権限を持っている必要があります。使用されるリソースのほとんどは、Aways Free Tier (コンピュート・インスタンス、VCN、Autonomous Database、オブジェクト・ストレージ、ロギング、リソース・マネージャ)で使用可能であるか、月次使用制限(ファンクション、APIゲートウェイ、ストリーミング、Vault、DevOps)の空き割当て層があります。
このシリーズの最初の部分では、Oracle Linux Cloud Developerイメージに基づくコンピュート・インスタンスのプロビジョニング、インバウンドおよびアウトバウンド・ネットワーク・アクティビティ用のオープン、およびアプリケーションによって生成されたHTTPリクエストを処理し、ロギングをOCIロギングに接続するGoアプリケーションの作成および実行について説明します。第2部では、ソフトウェア・エンジニアリング、OCI DevOpsサービスによるアプリケーションの構築とデプロイメントの自動化について説明します。このサービスは、Goソース・コードの格納、アプリケーション実行可能ファイルの構築、およびデプロイ可能なアーティファクトとして格納し、そのアーティファクトをコンピュート・インスタンスにデプロイするために使用されます。また、この記事では、OCI API Gatewayを介してアプリケーションのHTTPエンドポイントを公開する方法についても説明します。パート3では、Goでサーバーレス関数を作成し、OCIにデプロイする方法を示します。Go SDK for OCIが導入されました。まず、ローカルなスタンドアロンのGoアプリケーション用で、その後、リソース・プリンシパル認証を利用して関数から使用します。このSDKは、バケットの作成およびファイルの書込みおよび読取りのためにOCI Object Storageサービスと対話するために使用されます。
パート4では、GoアプリケーションとOracle Databaseの間の相互作用について説明します。これは、ローカル・データベースまたはオンプレミス・データベース、一部のクラウド・ベンダーのIaaSインスタンスで実行されているデータベース、またはOCI Autonomous Databaseです。標準のGo database/sqlパッケージをOracle Databaseのドライバとともに使用し、必要な構成の詳細をドライバにフィードすると、Oracle DatabaseのGoの利用は非常に簡単であることがわかります。パート2で説明したGoアプリケーションmyserverは、OCI上のAutonomous DatabaseインスタンスとOCIオブジェクト・ストレージ・サービスの両方と対話するように拡張されています。アプリケーションは、OCI用のGo SDKを使用して、オブジェクト・ストレージのバケットからファイルを読み取る(その後削除する)とともに、その内容に基づいてAutonomous Databaseにデータベース・レコードを作成します。
Go言語は、それに組み込まれたリレーショナル・データベースとのSQLインタラクションをサポートしています。標準パッケージ・データベース/SQLには、データベースへの接続、トランザクションの実行、進行中の操作の取消しなどを行うためのタイプと関数が含まれています。この同じパッケージは、MongoDBやCouchbaseなどの一部のNoSQLデータベースと同じ方法で作業するために使用できます。
このパッケージを通じてデータベースと対話するGoアプリケーションは、特定のデータベース製品の技術的な実装の詳細を必要としません。これらの詳細は、通常、そのデータベースのドライバに実装されます。アプリケーションは、データベースの接続に必要なドライバをインポートし、使用するドライバとデータベースの接続詳細を標準パッケージ・データベース/SQLに指示します。データベースとの対話のほとんどは、特定のデータベース・テクノロジに関係なく同じです。レコードはSQL DML文を使用して作成、更新および削除され、レコードはSQL問合せを介して取得されます。プロセス全体はデータベース間で同じですが、正確なSQL言語は異なる場合があります。これはおそらく、異なるデータベース製品間でGoアプリケーションを簡単に移行するための唯一の本当の障害です。
この項で説明するコードは、この記事シリーズに付随するコード・リポジトリのディレクトリ/applications/go-orcl-dbにあります。
GoアプリケーションによるSQL - DDL、DMLおよび問合せ
GoアプリケーションからOracle Databaseを使用する最も簡単なことは、1行の問合せです。このために必要なコードは次のようになります: package main
package main
import (
"database/sql"
"fmt"
)
func sqlOperations(db *sql.DB) {
var queryResultColumnOne string
row := db.QueryRow("SELECT to_char(systimestamp,'HH24:MI:SS') FROM dual")
err := row.Scan(&queryResultColumnOne)
if err != nil {
panic(fmt.Errorf("error scanning query result from database into target variable: %w", err))
}
fmt.Println("The time in the database ", queryResultColumnOne)
}
import文を使用すると、データベース/SQLパッケージが使用可能になります。sql.DBへのハンドルを使用すると、SQL問合せを簡単に実行でき(QueryRow)、結果をローカル変数にスキャンできます。特定のSQL文を除き、非常にシンプルでわかりやすく、データベース・ブランドに依存しません。この場合、Oracle固有のsystimestampが使用されます。
ここでは、dbパラメータの由来については説明しません。しばらくして、データベース・ドライバについて話し合い、そこですべてが明らかになります。
表の作成、レコードの挿入、レコードの問合せ、さらに多くのレコードへの作成、すべての行の問合せ、最後に表の削除を行う、より興味深い関数がここに表示されます。このコードは、コード・リポジトリのファイルoracle-database-client-app.goにあります。
package main
import (
"database/sql"
"fmt"
)
const createTableStatement = "CREATE TABLE TEMP_TABLE ( NAME VARCHAR2(100), CREATION_TIME TIMESTAMP DEFAULT SYSTIMESTAMP, VALUE NUMBER(5))"
const dropTableStatement = "DROP TABLE TEMP_TABLE PURGE"
const insertStatement = "INSERT INTO TEMP_TABLE ( NAME , VALUE) VALUES (:name, :value)"
const queryStatement = "SELECT name, creation_time, value FROM TEMP_TABLE
func sqlOperations(db *sql.DB) {
_, err := db.Exec(createTableStatement)
handleError("create table", err)
defer db.Exec(dropTableStatement) // make sure the table is removed when all is said and done
stmt, err := db.Prepare(insertStatement)
handleError("prepare insert statement", err)
sqlresult, err := stmt.Exec("John", 42)
handleError("execute insert statement", err)
rowCount, _ := sqlresult.RowsAffected()
fmt.Println("Inserted number of rows = ", rowCount)
var queryResultName string
var queryResultTimestamp time.Time
var queryResultValue int32
row := db.QueryRow(queryStatement)
err = row.Scan(&queryResultName, &queryResultTimestamp, &queryResultValue)
handleError("query single row", err)
if err != nil {
panic(fmt.Errorf("error scanning db: %w", err))
}
fmt.Println(fmt.Sprintf("The name: %s, time: %s, value:%d ", queryResultName, queryResultTimestamp, queryResultValue))
_, err = stmt.Exec("Jane", 69)
handleError("execute insert statement", err)
_, err = stmt.Exec("Malcolm", 13)
handleError("execute insert statement", err)
// fetching multiple rows
theRows, err := db.Query(queryStatement)
handleError("Query for multiple rows", err)
defer theRows.Close()
var (
name string
value int32
ts time.Time
)
for theRows.Next() {
err := theRows.Scan(&name, &ts, &value)
handleError("next row in multiple rows", err)
fmt.Println(fmt.Sprintf("The name: %s and value:%d created at time: %s ", name, value, ts))
}
err = theRows.Err()
handleError("next row in multiple rows", err)
}
func handleError(msg string, err error) {
if err != nil {
fmt.Println(msg, err)
os.Exit(1)
}
}
このコードは本質的に非常に機能しています。SQL文以外に、データベース固有の実装の詳細はありません。コードの半分はエラー処理であるようです。このコードがデータベースをどのように操作するかを理解するのは難しくありません。ただし、まだ操作するデータベースがなく、(したがって)接続して通信を処理するドライバもない点が異なります。まずローカル・データベースを実行し、次にドライバをGoアプリケーションに追加して、これを修正します。
ローカルOracle Databaseの実行
ローカルOracle Databaseを起動して実行するには、様々な方法があります。私が見つけた最も簡単な方法は、1つの非常にシンプルで簡単な文でローカル・データベースを実行できるDockerコンテナ・イメージを使用することです。
docker run -d -p 1521:1521 -e ORACLE_PASSWORD=TheSuperSecret1509! gvenzl/oracle-xe
これにより、Oracle Database XE 21cインスタンス(少なくとも、21cが使用可能な最新のコンテナ・イメージの場合に、書込み時に実行されるインスタンス)が実行され、SYSおよびSYSTEMのパスワードが指定された値に設定されます。データベースは、localhostのポート1521で使用できます。
OracleのGerald Venzlは、Oracle Databaseのスリム・バージョン(XEエディション)を実行する一連の(Docker)コンテナ・イメージを保持しています。XEエディションは無料で使用できます(最大20GBのデータで、最大2個のCPUスレッドと2 GB RAMを使用します)。「gvenzl/oracle-XEの紹介: Oracle Database XE Dockerイメージ」というタイトルの記事で、これらのイメージとその使用方法について説明します。
次のステップに従って、ローカルOracle Databaseが稼働していることを確認します。
```console
docker exec -it /bin/bash
```
```console
sqlplus system/TheSuperSecret1509! as sysdba
```
```sql
create user demo identified by demo default tablespace users temporary tablespace temp
/
grant connect, resource to demo
/
```
次に、Goアプリケーションからこのデータベースに接続します。
Note: You may be interested in installing the Oracle VS Code extension that allows making connections to Oracle Databases – local and remote – browse their contents and interact with them similar to SQL Developer and other desktop tools.
Oracle Database用のドライバの追加
Oracle Database用の公式Goドライバはありません。少なくともOracleによって公開または承認されているドライバはありません。Goデータベース・ドライバの非公式なリストには、Oracle Database用の4つのエントリがあります。3つはOracle Clientライブラリのインストールが必要ですが、1つはインストールする必要はありません。まず、データベースとのすべての通信を単独で処理する純粋なドライバであるgo-oraという最後のドライバで作業しましょう。go-oraの詳細は、GitHubのgo-oraホームページから入手できます。その後、godror、ライブラリのインストールが必要なドライバ、およびGo用のOracle Databaseドライバの中で最も顕著なドライバについても説明します。
Go-oraドライバは、次を使用してGoアプリケーションに追加できます。
go get github.com/sijms/go-ora/v2
これにより、パッケージがダウンロードされ、go.modファイルにrequireエントリが追加されます。私の場合、次のようになります。
module oracle-database-client
go 1.16
require (
github.com/sijms/go-ora/v2 v2.4.16 // indirect
)
ファイルoracle-database-client-app.goと同じディレクトリにあるpure-oracle-database-client.goという新しいファイルで、次のコードはgo-oraを介してローカルOracle Databaseとの対話を処理します。ドライバ・パッケージがインポートされ、oracleを暗黙的に参照するsql.Openへのコールによって、選択したドライバとしてgo-oraが選択されます。
パラメータdbParamsは、接続に使用する構成設定(ユーザー名とパスワードを含む)、データベース・ホストとポートおよびサービス名のマップで構成されます。接続文字列は、これらの要素を使用して構成され、sql.Openのコールで使用されます。db.Pingへの後続の呼出しは、データベースとの通信を実際に確立する最初の試行です。このコールが成功すると、実際のデータベース・アクションの準備が整います。
package main
import (
"database/sql"
"fmt"
"net/url"
_ "github.com/sijms/go-ora/v2"
)
func GetSqlDBWithPureDriver(dbParams map[string]string) *sql.DB {
connectionString := "oracle://" + dbParams["username"] + ":" + dbParams["password"] + "@" + dbParams["server"] + ":" + dbParams["port"] + "/" + dbParams["service"]
db, err := sql.Open("oracle", connectionString)
if err != nil {
panic(fmt.Errorf("error in sql.Open: %w", err))
}
err = db.Ping()
if err != nil {
panic(fmt.Errorf("error pinging db: %w", err))
}
return db
}
接続と実行中
データベースが実行中で、純粋なOracle Databaseドライバで動作する関数があります。ここで、oracle-database-client-app.goに戻り、関連付けます。
このファイルに関数mainを追加します。GetSqlDBWithPureDriverをコールして、マップlocalDBで定義されたデータベース接続詳細を使用してsql.DBインスタンスを作成します。データベース構成に合せてこれらの値を変更します。ファンクション・コールは、DB変数を*sql.DBで設定します。この変数は、さらにSQL操作に使用できます。
すべてのデータベース相互作用が完了したら、接続をクローズしてリソースを解放する必要があります。これが完了したことを確認するために、GetSqlDBWithPureDriverのコール直後にdefer in function mainがdb.Close()のコールとともに追加されます。dbを渡す関数sqlOperationsをコールすると、2つのセクションで説明した関数が表示され、データベースが実際に相互作用します。
var localDB = map[string]string{
"service": "XE",
"username": "demo",
"server": "localhost",
"port": "1521",
"password": "demo",
}
func main() {
db := GetSqlDBWithPureDriver(localDB)
defer func() {
err := db.Close()
if err != nil {
fmt.Println("Can't close connection: ", err)
}
}()
sqlOperations(db)
}
go run *.goを使用して、コマンドラインからアプリケーションを実行します。出力は次のようになります。
go run *.go
Inserted number of rows = 1
The name: John, time: 2022-04-25 05:31:02.489289 +0000 UTC, value:42
The name: John and value:42 created at time: 2022-04-25 05:31:02.489289 +0000 UTC
The name: Jane and value:69 created at time: 2022-04-25 05:31:02.506039 +0000 UTC
The name: Malcolm and value:13 created at time: 2022-04-25 05:31:02.509098 +0000 UTC
GoDrOrドライバの操作
go-oraの一般的な代替手段は、Goパッケージのgodrorです(以前はgoracleと呼ばれていましたが、商標の問題により名前が変更されました。Oracle Corporationでは、誰もoracleを名前で使用することを望んでいません)。このパッケージは、oracleまたはgodrorに対してsql.Openが実行されるときにデータベース/SQLで使用できるOracle Databaseドライバも提供します。このパッケージは、go-oraとは異なり、Goアプリケーションを実行しているシステムにOracle Instant Clientライブラリをインストールする必要があります。
GoDrOrドライバは、Oracle Database Programming Interface for C(ODPI-C)を使用します。Oracle Corporationが管理するCコードのオープン・ソース・ライブラリであり、Oracle Databaseドライバおよびユーザー・アプリケーションに対する共通のOracle Call Interface (OCI)機能の使用を簡略化します。GoDrOrを使用する場合、ODPI-Cをインストールしたり、その存在を認識する必要はありません。ただし、ドライバを含むGoアプリケーションが実行されている環境には、Oracle Clientライブラリが含まれている必要があります。
最も単純なOracle Clientは無料のOracle Instant Clientです(Oracle Instant Clientの概要ページを参照)。「Basic」または「Basic Light」パッケージのみが必要です。Oracle Clientライブラリは、任意のOracle Databaseインストールまたは完全なOracle Clientインストールでも使用できます。Linuxの詳細なインストール手順は、Oracle Databaseドキュメントforリリース21c–Database Clientインストレーション・ガイドfor Linux– Oracle Instant Clientのインストールを参照してください。
ODPI-Cは、使用可能なOracle Clientライブラリを実行時に動的にロードします。Oracle Clientライブラリは、ODPI-Cライブラリ(またはアプリケーション・バイナリ)と同じディレクトリで検索されます。見つからない場合は、標準のオペレーティング・システム検索パス(Windowsの場合はPATH、Linuxの場合はLD_LIBRARY_PATHなど)で検索されます。最後に、Windows以外のプラットフォームでは、$ORACLE_HOME/libも検索されます。ODPI-CでOracle Clientライブラリを検索できることを確認する方法の詳細は、ODIP-C GitHubホーム –ODPI-Cインストールを参照してください。
go-oraからgodrorに切り替えるためにアプリケーションに加える必要がある変更は最小限です。
まず、godrorドライバがGoアプリケーションに追加されます。
github.com/godror/godror
これにより、パッケージがダウンロードされ、go.modファイルにrequireエントリが追加されます。
次に、同じアプリケーション・ディレクトリにgodror-based-oracle-database-client.goという新しいファイルを作成します。これは、go-oraドライバを介した接続の詳細を含むpure-oracle-database-client.goと非常によく似ています。
この新しいファイルの内容:
package main
import (
"database/sql"
"fmt"
_ "github.com/godror/godror"
)
func GetSqlDBWithGoDrOrDriver(dbParams map[string]string) *sql.DB {
var db *sql.DB
var err error
connectionString := "oracle://" + dbParams["username"] + ":" + dbParams["password"] + "@" + dbParams["server"] + ":" + dbParams["port"] + "/" + dbParams["service"]
db, err = sql.Open("oracle", connectionString)
err = db.Ping()
if err != nil {
panic(fmt.Errorf("error pinging db: %w", err))
}
return db
}
Godrorパッケージのインポートは、go-oraのインポートと異なります。残りのコードは以前とまったく同じです。
Note: when we use the Oracle Wallet and change to encrypted communications with the Autonomous Database, there will be more differences between the code used with the two drivers.
最後に、アプリケーションがgo-oraの使用を停止し、godrorの使用を開始するには、GetSqlDBWithGoDrOrDriverをコールして、ある行をコメントアウトまたは削除し、別の行をファンクションmainに追加する必要があります。
func main() {
//db := GetSqlDBWithPureDriver(localDB)
db := GetSqlDBWithGoDrOrDriver(localDB)
go run *.goでアプリケーションを再度実行すると、以前と同じ出力が表示されます。Oracle Instant Clientが現在関与しているという事実は明らかではありません。この動作は、特定の操作のパフォーマンスなどの非機能的な違いがある場合でも、明らかに変更されません。
データベース・トランザクション管理
前述の説明からはっきりしないのは、実際にデータベースにデータをコミットしたことがないことです。すべてのSQLアクションは、単一のデータベース・セッションで実行されました。表を作成および削除した2つのDDL操作は、トランザクションを暗黙的にコミットしましたが、どの挿入文もコミットされませんでした。一部のデータベースには自動コミット設定があり(一部はデフォルトとしても)、すべてのDML操作が自動コミットされるトランザクションに変わります。Oracle Databaseとは異なります。データベース・レコードに加えられた変更をコミットするには、これらの変更を明示的にコミットするか、永続的な影響が最終的に望ましくない場合にロールバックする必要があります。Goアプリケーションでは、データベースでトランザクション(sql.Tx)を開始し、そのトランザクションでDML文を実行し、最後にトランザクションをコミットまたはロールバックすることで、データベース・トランザクションを明示的に操作できます。例:
ctx := context.Background()
tx, err := db.BeginTx(ctx, nil)
err = tx.ExecContext(ctx, DMLStatement, ... bind parameter values)
err = tx.ExecContext(ctx, AnotherDMLStatement, ... bind parameter values)
err = tx.Commit() // or tx.Rollback()
Goアプリケーションをローカル(または従来は接続されていた)と通信することは、Oracle Databaseがそれほど難しくありませんでした。Oracle Walletを使用するクライアント(OCI上のOracle Autonomous Databaseインスタンスなど)からの暗号化通信用に構成されたデータベースは、対話が難しくありません。Oracle Walletファイルと連携するようにコードを拡張する必要があります。もちろん、Autonomous Databaseインスタンスを実行して、関連するOracle Walletを取得する必要があります。
OCIで無料のAutonomous Databaseを実行
Autonomous Databaseインスタンスの実行は、ローカル・データベースの実行よりもほぼ簡単です。ATPインスタンスは、いくつかの方法(OCI CLIやTerraformなど)で作成できますが、最も簡単な方法は、おそらくOCIブラウザ・コンソールを使用することです。
Note: Tim Hall provides a good description in his article Oracle Cloud : Autonomous Transaction Processing (ATP) – Create Service, and there are many more to be found.
Always Free ATPインスタンスを作成します。
コンソールの検索ボックスにautと入力し、「*Autonomous Database Features*」に移動し、「Create Autonomous Database」ボタンをクリックします。
作成フォームで、表示名(go-on-oci-dbの場合もある)とデータベース名を指定し、ワークロード・タイプとして「トランザクション処理」を選択し、「Always Free」トグルをアクティブに切り替え、ADMINのパスワードを指定します(よく覚えておいてください)。すべての場所からのネットワーク・アクセス・タイプ「セキュア・アクセス」を受け入れ、「相互TLS (mTLS)認証が必要」チェック・ボックスが選択されていることを確認します。
「Autonomous Databaseの作成」ボタンを押してデータベースを作成すると、プロビジョニング・ステータスが表示されます:
データベースが使用可能になるまでに1分未満かかります。
接続詳細を含むDatabase Walletのダウンロード
mTLS相互作用に必要なSSL証明書を含むデータベース・ウォレットが必要です。ATPインスタンスのウォレットをダウンロードします。まず、OCIコンソールの「ATP」ページで「DB接続」ボタンをクリックし、「ウォレットのダウンロード」をクリックします。
ウォレットのパスワードを指定します。これは後でウォレットを読み取るために必要になる場合があります。このパスワードにも接続してください。ただし、この記事で説明する手順でこのパスワードは必要ありません。
zipファイルを保存し、すぐに使用します。
Autonomous Databaseでのデモ・ユーザー・アカウントの作成
自律型データベースにデモ・ユーザー・アカウントを作成できます。これは、次のステップで実行できます。
create user demo identified by thePassword1 default tablespace users temporary tablespace temp
/
grant connect, resource to demo
/
ALTER USER DEMO QUOTA UNLIMITED ON DATA
/
対話するOracle DatabaseをOracle Walletを使用して接続する必要がある場合、Oracle Walletのファイル・システムの場所をドライバに渡す必要があります。より正確には、ウォレットの一部であるファイルcwallet.ssoを含むディレクトリへのパスを指定する必要があります。通常、ウォレットはzipアーカイブで提供されます。このアーカイブを抽出(または少なくともこのファイルが必要)し、そのファイルを含むディレクトリへのパスをwalletLocationと呼びます。この時点で、ウォレットzipファイルからcwallet.ssoを抽出し、このファイルをGoアプリケーションからアクセス可能な場所に移動します。Goアプリケーション自体と同じディレクトリにある場合もあります。これは本番グレードのアプリケーションのベストプラクティスではありませんが、この記事の目的で十分です。
提供する必要がある自律型データベースの接続詳細は、ローカル・データベースで以前使用されていたものと同じ要素セットで構成されます。データベース・サービス名は、ウォレットzipファイルのtnsnames.oraファイル、またはOCIコンソールの「ATP DB接続」ページのservice_nameにあります。serverプロパティーの値は、これらの場所でホストとして使用できます。
プロパティが収集されると、localDBのすぐ下のoracle-database-client-app.goファイルに次のマップ定義を追加できます。
var autonomousDB = map[string]string{
"service": "k8j2fvxbaujdcfy_goonocidb_medium.adb.oraclecloud.com",
"username": "demo",
"server": "adb.us-ashburn-1.oraclecloud.com",
"port": "1522",
"password": "thePassword1",
"walletLocation": ".", // when the *.sso file has been moved into the application directory; otherwise provide the absolute directory path
}
Driver go-oraを使用したAutonomous Databaseとの対話
接続文字列にウォレットの場所を含め、セキュアな通信プロトコルを構成するには、go-oraドライバ構成を少し拡張する必要があります。
func GetSqlDBWithPureDriver(dbParams map[string]string) *sql.DB {
connectionString := "oracle://" + dbParams["username"] + ":" + dbParams["password"] + "@" + dbParams["server"] + ":" + dbParams["port"] + "/" + dbParams["service"]
if val, ok := dbParams["walletLocation"]; ok && val != "" {
connectionString += "?TRACE FILE=trace.log&SSL=enable&SSL Verify=false&WALLET=" + url.QueryEscape(dbParams["walletLocation"])
}
db, err := sql.Open("oracle", connectionString)
...
アプリケーションをAutonomous Databaseに対して実行し、そのTEMP_TABLEアクロバットをクラウドで実行するには、メイン関数を少し変更する必要があります:
func main() {
db := GetSqlDBWithPureDriver(autonomousDB)
//db := GetSqlDBWithGoDrOrDriver(localDB)
...
つまり、GetSqlDBWithPureDriverへのコールでlocalDB参照をautonomousDBに置き換えます。
次に、go run *.goを使用してアプリケーションを再度実行します。結果は、ローカル・データベースに対する前とまったく同じになりますが、各データベース相互作用でレイテンシが導入されるため、生成には多少時間がかかります。
ドライバのgodrorを使用したAutonomous Databaseとの対話の実行
Godrorドライバでは、go-oraと比較してOracle Walletの操作に若干異なる設定が使用されます。ファイルgodror-based-oracle-database-client.goのファンクションGetSqlDBWithGoDrOrDriverは、このケースを処理するために拡張されています。
func GetSqlDBWithGoDrOrDriver(dbParams map[string]string) *sql.DB {
var db *sql.DB
var err error
if val, ok := dbParams["walletLocation"]; ok && val != "" {
db, err = sql.Open("godror", fmt.Sprintf(`user="%s" password="%s"
connectString="tcps://%s:%s/%s?wallet_location=%s"
`, dbParams["username"], dbParams["password"], dbParams["server"], dbParams["port"], dbParams["service"], dbParams["walletLocation"]))
}
if val, ok := dbParams["walletLocation"]; !ok || val == "" {
connectionString := "oracle://" + dbParams["username"] + ":" + dbParams["password"] + "@" + dbParams["server"] + ":" + dbParams["port"] + "/" + dbParams["service"]
db, err = sql.Open("oracle", connectionString)
}
err = db.Ping()
...
Autonomous Databaseに対してgodrorドライバを使用してアプリケーションを実行し、クラウドでTEMP_TABLEアクロバットを実行するには、メイン関数を少し変更する必要があります:
func main() {
//db := GetSqlDBWithPureDriver(autonomousDB)
db := GetSqlDBWithGoDrOrDriver(autonomousDB)
...
次に、go run *.goを使用してアプリケーションを再度実行します。結果は再びgo-oraドライバーとまったく同じになるだろうが(少なくとも私の環境では)、go-oraを通じた行動は、godrorを通じた同じ行動よりも大幅に速いようだ。
コード・リポジトリには、ディレクトリ/applications/data-serviceにdata-serviceというアプリケーションが含まれています。このアプリケーションは、このシリーズの記事1と2で作業したmyserverアプリケーションの拡張です。アプリケーションは以前と同様にHTTPリクエストを処理し、今回は単純なデータAPIも実装します。PUT、POSTおよびDELETEリクエストを使用して、このアプリケーションを使用して、Oracle DatabaseのPEOPLEという表から個人レコードを作成、更新および削除できます。GETリクエストを使用すると、すべてのユーザーの現在の詳細を取得できます。
まず、アプリケーションの興味深い要素について簡単に見てから、ローカルで実行します。次のステップでは、このアプリケーションをコンピュート・インスタンスのOCIで実行します。OCIへのデプロイメントに関して、Autonomous Databaseとのやり取りがあるアプリケーションに関して特別なことは何もないことがわかります。または、少なくとも、OCI Key Vaultを使用してOracle Walletの詳細を安全に保持するこのシリーズの次の賦払までは、インスタンス・プリンシパル・ベースの認可のおかげで、アプリケーションは実行時に取得できます。ただし、現時点では、ウォレットはソース・コード・リポジトリに含まれ、ビルドおよびデプロイメント・パイプラインで処理されます。これは良い方法ではなく、次の記事で修正されます。
アプリケーションがデプロイされたら、コンピュート・インスタンスに直接アクセスできるかどうかを確認します。公的にサービスを直接公開しない(非公開)に関するベスト・プラクティスを適用するために、データ・サービス、特にデータベース基盤の機能につながるもう1つのルートでAPI Gatewayを拡張します。
この項の最後にOCIで達成した最後の状況は、次のようになります。
データ・サービスを検査し、ATPインスタンス用に構成します。
ファイルdata-server.goは、アプリケーションで新しく追加されました。これには、データベースと対話し、パス・データ(DATA_PATH)にあるアプリケーションへのHTTPリクエストを処理するためのすべてのロジックが含まれます。DataHandlerファンクションのメイン・ファンクションに登録すると、データ処理機能が統合されます。
http.HandleFunc(DATA_PATH, DataHandler)
関数mainは、次の初期化ステップでも拡張されています。
func main() {
db := GetSqlDBWithGoDrOrDriver(autonomousDB)
defer func() {
err := db.Close()
if err != nil {
fmt.Println("Can't close connection: ", err)
}
}()
InitializeDataServer(db)
...
サーバー・アプリケーションを起動すると、データベース接続が作成され、データ・サーバーが設定されます。アプリケーションでは、Godrorドライバが使用されます。デプロイメント・ターゲットであるコンピュート・インスタンスがOracle Linux Cloud Developerイメージに(シリーズの一部に戻って)作成され、Oracle Instant Clientがプリインストールされているという事実を利用します。
実行するためにアプリケーションを追加する必要があるのは、次のとおりです。
その後、次を使用してアプリケーションをローカルに実行できます。
go run *.go
アプリケーションが起動し、職務のレポートが作成されます。
別のターミナル・ウィンドウで、curl文を使用してPerson APIと対話します。これらのHTTPリクエストにより、Mickey MouseとBugs Bunnyの2つのレコードが作成されます。ミッキーの記録は一度更新。両方のレコードが1回取得されます。その後、両方とも削除されます。最後のGETリクエストでは、データは返されません。
curlリクエストを追加するか、すべてを実行しないでください。たとえば、SQLワークシートで、Person APIによって予期されるデータベース・レコードが作成されたかどうかを確認できます。
curl -X "PUT" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse", "age":93, "comment": "Cartoon Character"}' localhost:8080/data
curl -X "PUT" -H "Content-Type: application/json" -d '{"name":"Bugs Bunny", "age":84, "comment": "an animated cartoon character created in the late 1930s by Leon Schlesinger Productions (later Warner Bros. Cartoons) and voiced originally by Mel Blanc."}' localhost:8080/data
curl -X "POST" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse", "age":93, "comment": "Cartoon Character and Movie Star, created in 1928 by Walt Disney and first appearing in Steamboat Willie; he is the mascot of The Walt Disney Company. His partner is Minnie and he has a pet dog called Pluto "}' localhost:8080/data
curl -X "GET" localhost:8080/data?name=Mickey+Mouse
curl -X "GET" localhost:8080/data?name=Bugs+Bunny
curl -X "DELETE" -H "Content-Type: application/json" -d '{"name":"Bugs Bunny"}' localhost:8080/data
curl -X "DELETE" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse"}' localhost:8080/data
curl -X "GET" localhost:8080/data?name=Mickey+Mouse
デプロイと実行につながるコミット、プッシュおよびビルド
GitHubの記事ソース・リポジトリのすべてのコードがこのシリーズの2番目の記事でOCIコード・リポジトリにコミットされたため、このmyserverアプリケーションのバリアントはすぐに使用でき、コードはすでにOCI DevOpsコード・リポジトリにあります。ただし、ファイルcwallet.sso (Autonomous DatabaseインスタンスのOracle Wallet)を追加し、データベース接続の詳細を提供するためにファイルdata-server.goを更新しました。ビルド・パイプラインをOCIで使用してアプリケーションをビルドし、その後デプロイする前に、まず新しいファイルを追加し、変更済ファイルとこの追加済ファイルの両方をコミットして、変更をOCI DevOpsコード・リポジトリにプッシュする必要があります。
これらのgit追加、コミットおよびプッシュ・アクションの後、コード・リポジトリのgo-on-oci-repoには、変更したcwallet.ssoおよびdata-service.goが含まれている必要があります。
最初にOCI DevOpsビルド・パイプラインについて説明したときに、記事2で設定されたビルド・パイプライン・ビルド-myserverを再利用できるようになりました。ただし、現在のパイプラインでは、デフォルトの場所にあるビルド仕様ファイルが想定され、修正されたmyserverアプリケーションでは実行されません。
パイプラインは、新しいアーティファクト(ディレクトリ/applications/data-serviceのGoソースからビルドされ、ウォレット・ファイルおよびWebサイト・サブディレクトリを含む実行可能ファイルを含むzipファイル)を生成します。パイプラインは、アーティファクトをコンピュート・インスタンスに移動するデプロイメント・パイプラインをトリガーし、アプリケーションを/tmp/yourserverディレクトリにコピーして、アプリケーションを実行します。デプロイメント・パイプライン・パラメータHTTP_SERVER_PORTで指定されたポート(またはパラメータが設定されていない場合は8080)でHTTPリクエストのリスニングを開始します。
VMのパブリックIPアドレスでPerson APIにアクセスできます(まだ公開されている場合)。
curl -X "GET" :8095/data?name=Mickey+Mouse
APIゲートウェイにルートを作成して、個人APIへの適切なパブリック・アクセスを提供できます。APIで処理するすべてのメソッドをルート定義に追加してください。
デプロイメントが更新されると、Person APIはhttps://
PostmanなどのCurlおよびその他のHTTPツールを使用して、すべての方法を使用して個人レコードを作成、更新、取得および削除できます。
この記事の最後のステップは、OCI Object Storageサービスとのやり取り(前の記事で紹介)と、単一のGoアプリケーションのAutonomous Databaseインスタンスに対する操作を組み合せたもので、最初にローカルで実行され、次にOCIのコンピュート・インスタンスにデプロイされて実行され、API Gatewayを介して公開されます。提供される機能: オブジェクトの名前とオブジェクト・ストレージのバケットを含むHTTP GETリクエストを送信します。オブジェクトは、次の形式のユーザーに関するデータを含むJSONファイルである必要があります:
[
{
"name": "Jasper",
"age": 19,
"comment": "Haute Couture"
},
{
"name": "James",
"age": 3,
"comment": "Golden retriever"
}
]
ファイルが読み取られ、各JSONエントリのAutonomous Databaseの表PEOPLEにレコードが作成されます。
実行するには、アプリケーションに追加する必要があります。
その後、次を使用してアプリケーションをローカルに実行できます。
go run *.go
アプリケーションが起動し、職務のレポートが作成されます。
別の端末ウィンドウで、curl文を使用して新しいPersonsファイル・プロセッサAPIと対話します。HTTPリクエストは、処理するJSONデータを含むバケットの名前およびオブジェクトを渡す必要があります。このサービスは、ファイルをフェッチし、その内容を解析し、自律型データベースのPEOPLE表のレコードを作成または更新します。
curl "localhost:8080/people?objectName=sample-persons.json&bucketName=the-bucket"
データAPIのコールを使用して、データ・レコードを検査できます。
curl localhost:8080/data?name=Martha
SQL Developerワークシートでも同じことが可能です。
表PEOPLEのレコード作成(または更新)を処理する関数PeopleJSONProcessorに関心がある場合があります。Oracle固有のバルクDMLアプローチ(godrorドライバでサポートされる構文)を使用します。ここでは、バインド・パラメータごとに値の配列が渡され、すべてのレコードが単一のDML文で作成されます。非常に効率的です。
func PeopleJSONProcessor(peopleJson []byte) {
var persons []Person
json.Unmarshal(peopleJson, &persons)
nameVals := make([]string, len(persons))
ageVals := make([]int, len(persons))
descriptionVals := make([]string, len(persons))
for i, person := range persons {
ageVals[i] = person.Age
nameVals[i] = person.Name
descriptionVals[i] = person.JuicyDetails
}
database.Exec(`MERGE INTO PEOPLE t using (select :name name, :age age, :description description from dual) person
ON (t.name = person.name )
WHEN MATCHED THEN UPDATE SET age = person.age, description = person.description
WHEN NOT MATCHED THEN INSERT (t.name, t.age, t.description) values (person.name, person.age, person.description) `,
nameVals, ageVals, descriptionVals)
}
次に、このアプリケーションをOCIに持ち込み、前の項でも使用したコンピュート・インスタンスにします。準備として必要なステップは次のとおりです。
これらのgit追加、コミットおよびプッシュ・アクションの後、コード・リポジトリのgo-on-oci-repoには、変更したcwallet.ssoおよびdata-service.goが含まれている必要があります。
以前に使用したビルド・パイプライン・ビルド-myserverを再利用できるようになりました。前述のとおり、ビルド仕様ファイルへの参照を更新する必要があります。
ビルド実行を開始します。必要に応じて、パラメータMYSERVER_VERSIONの新しいバージョンを設定します。
パイプラインは、新しいアーティファクト(ディレクトリ/applications/people-file-processorのGoソースからビルドされ、ウォレット・ファイルおよびWebサイト・サブディレクトリを含む実行可能ファイルを含むzipファイル)を生成します。パイプラインは、アーティファクトをコンピュート・インスタンスに移動するデプロイメント・パイプラインをトリガーし、アプリケーションを/tmp/yourserverディレクトリにコピーして、アプリケーションを実行します。デプロイメント・パイプライン・パラメータHTTP_SERVER_PORTで指定されたポート(またはパラメータが設定されていない場合は8080)でHTTPリクエストのリスニングを開始します。
VMのパブリックIPアドレスでAPIにアクセスできます(公開されている場合)。人事ファイル・プロセッサへのアクセスを公開するには、APIゲートウェイにルートを追加することをお薦めします:
パスを/personnel-file-handlerとして定義します。GETメソッドがサポートされる必要があります。ルートのタイプはHTTPです。URLは、http://<Public IP for Compute Instance>:8095/peopleです。デプロイメント・パイプラインdeploy-myserver-on-go-app-vmのHTTP_SERVER_PORTの値を確認します。8095に設定されていない場合は、アプリケーションに適切なポート番号を使用するようにURL値を変更します。
「次へ」、「変更の保存」の順に押します。APIゲートウェイのデプロイメントがリフレッシュされるまでに少し時間がかかります。オブジェクト・ストレージ・バケットからファイルを読み取るサービスは、JSONコンテンツを処理し、このファイル内のエントリに対してAutonomous Databaseインスタンスの表PEOPLEにレコードを作成するサービスを、https://<public endpoind of API Gateway>/my-api/personnel-file-handler?objectName=sample-persons.json&bucketName=the-bucketへの単純なHTTP GETリクエストでトリガーできます。
コールを行う効果は、同じデータベース内の同じ表からレコードを読み取るユーザーAPIを介して検査できます: https://<public endpoind of API Gateway>/my-api/person?name=Jasper。
OCIに現在デプロイされている内容のエンドツーエンドの図を次の図に示します。
画像には表示されないものがあり、注意することが重要です。
次の記事では、OCI Key Vaultについて説明します。OCI Key Vaultは、Oracle Walletを格納し、デプロイメント時(またはランタイム時)にアプリケーションで使用できるようにするためのより優れた方法を提供します。
この記事では、従来のアプリケーションまたは自律型アプリケーションであるGoアプリケーションからOracle Databaseとどのように相互作用できるかを説明しています。GoアプリケーションからローカルOracle Databaseへの接続(およびAutonomous Databaseへの接続)が、ドライバおよび場合によってはサポートするライブラリを使用してどのように行われるか、およびGoアプリケーションの快適さからこれらのデータベースでDDLおよびDML SQL操作をどのように実行できるかを確認しました。(自律型)データベース資格証明を適切に管理するためのOracle Walletの使用について説明しました。OCIコンピュート・インスタンスで実行され、Go SDK for OCIとObject Storage Serviceをやり取りし、OCI DevOpsを介して自動的にデプロイされるAutonomous Databaseを操作するアプリケーションは、記事の詳細を提供します。
このシリーズの第5および最後の記事では、Goアプリケーションが対話できるOCIサービスがさらに2つ追加されています。OCI Streamingは、異なるマイクロサービスとその他のコンポーネント間の対話を分離できる大容量ストリーミング・メッセージ・ブローカであり、Oracle Walletなどのシークレットをデータベース資格証明で管理するためのOCI Key Vaultです。また、この記事では、管理対象OCI Kubernetes Enginer (OKE)のシェイプで、VMおよびサーバーレス機能の横にある3番目のタイプのアプリケーション・プラットフォームを紹介し、DevOps Deployment Pipelinesが自動化された方法でGoアプリケーションをOKEにデプロイする方法を示します。