Utilisation d'applications Go avec Oracle Database et Oracle Cloud Autonomous Database

Il s'agit de la quatrième partie d'une série de cinq parties sur Go et Oracle Cloud Infrastructure (OCI). Cette série explique comment créer et exécuter des applications Go sur Oracle Cloud Infrastructure dans des instances de calcul, en conteneur sur Kubernetes ou en tant que fonctions sans serveur. Les articles expliquent comment automatiser la création et le déploiement de ces applications Go à l'aide d'OCI DevOps. Un sujet important est de savoir comment utiliser les services OCI des applications Go, à la fois celles exécutées sur OCI et celles exécutées ailleurs. Les services OCI abordés incluent Object Storage, Streaming, Key Vault et Autonomous Database.

objet way-to-go-on-oci

Afin de suivre ces articles, les lecteurs doivent avoir au moins des connaissances de base sur la façon de créer des applications Go. On suppose que les lecteurs ont accès à leur propre environnement de développement Go. Certains des exemples et captures d'écran mentionneront spécifiquement VS Code comme outil de développement. Cependant, d'autres éditeurs et IDE peuvent également être utilisés. Le code Go présenté dans ces articles démontre un certain nombre de mécanismes dans leur forme la plus simple pour une clarté maximale et avec les moins de dépendances. Les lecteurs ne doivent pas s'attendre à une fonctionnalité significative ou à un code prêt pour la production.

Cette série explique comment accéder à OCI. Pour tester les exemples, les lecteurs doivent avoir accès à une location OCI avec des droits d'accès permettant de créer les ressources OCI abordées dans ces articles. La plupart des ressources utilisées sont disponibles dans le niveau Toujours gratuit (instance de calcul, VCN, Autonomous Database, Object Storage, Logging, Resource Manager) ou disposent d'un niveau d'affectation gratuit pour une utilisation mensuelle limitée (fonctions, passerelle d'API, Streaming, Vault, DevOps).

La première partie de cette série décrit le provisionnement d'une instance de calcul en fonction de l'image Oracle Linux Cloud Developer, son ouverture pour l'activité réseau entrante et sortante, ainsi que la création et l'exécution d'une application Go qui traite les demandes HTTP et la connexion de la journalisation produite par l'application à OCI Logging. La deuxième partie traite de l'ingénierie logicielle, de l'automatisation de la création et du déploiement de l'application avec le service OCI DevOps. Ce service est utilisé pour stocker le code source Go, créer l'exécutable de l'application et le stocker en tant qu'artefact déployable, puis déployer cet artefact vers une instance Compute. Cet article explique également comment exposer une adresse HTTP pour l'application via une passerelle d'API OCI. La troisième partie explique comment créer des fonctions sans serveur dans Go et les déployer sur OCI. Le kit SDK Go pour OCI est introduit, d'abord pour les applications Go locales et autonomes, puis pour une utilisation à partir de fonctions, en tirant parti de l'authentification par principal de ressource. Ce kit SDK est utilisé pour interagir avec le service OCI Object Storage afin de créer des buckets, d'écrire et de lire des fichiers.

La quatrième partie, que vous lisez actuellement, traite de l'interaction entre votre application Go et Oracle Database. Il peut s'agir d'une base de données locale ou sur site, d'une base de données exécutée sur les instances IaaS d'un fournisseur cloud ou d'une instance OCI Autonomous Database. En utilisant le package standard Go database/sql avec un pilote pour Oracle Database et en fournissant les détails de configuration requis au pilote, il s'avère que tirer parti de n'importe quelle base de données Oracle Database à partir de Go est assez simple. Le serveur myserver d'application Go abordé dans la deuxième partie est étendu pour interagir avec une instance Autonomous Database sur OCI et le service OCI Object Storage. L'application utilise le kit SDK Go pour OCI pour lire des fichiers (et les enlever ensuite) d'un bucket sur Object Storage et créer des enregistrements de base de données dans Autonomous Database en fonction de leur contenu.

Application Go locale parlant à la base de données locale

Le langage Go prend en charge les interactions SQL avec les bases de données relationnelles qui y sont intégrées. La base de données/sql de package standard inclut des types et des fonctions permettant de se connecter à des bases de données, d'exécuter des transactions, d'annuler une opération en cours, etc. Ce même package peut être utilisé pour travailler de la même manière avec certaines bases de données NoSQL telles que MongoDB et Couchbase.

Une application Go qui interagit avec une base de données via ce package n'a pas besoin de détails d'implémentation technique pour un produit de base de données spécifique. Ces détails sont généralement implémentés dans un pilote pour cette base de données. L'application importe le pilote requis pour la connexion à la base de données et indique au package standard database/sql le pilote à utiliser et les détails de connexion de la base de données. La plupart des interactions avec la base de données sont les mêmes, quelle que soit la technologie de base de données. Les enregistrements sont créés, mis à jour et supprimés via des instructions LMD SQL, et les enregistrements sont extraits via des requêtes SQL. Le processus global est le même entre les bases de données, mais le dialecte SQL exact peut varier. C'est probablement le seul obstacle réel pour déplacer facilement les applications Go entre différents produits de base de données.

Le code abordé dans cette section se trouve dans le répertoire /applications/go-orcl-db du référentiel de code qui accompagne cette série d'articles.

L'application Go exécute des instructions SQL : DDL, DML et Query

La chose la plus simple à faire avec une Oracle Database à partir d'une application Go est d'interroger une seule ligne. Voici à quoi ressemble le code requis : 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)
}

L'instruction import rend le package database/sql disponible. A l'aide du descripteur de sql.DB, une requête SQL peut facilement être exécutée (QueryRow) et le résultat peut être analysé en variables locales. Assez simple, simple et indépendant de la marque de la base de données, à l'exception de l'instruction SQL spécifique, qui utilise dans ce cas l'horodatage systimestamp spécifique d'Oracle.

Pour l'instant, ne nous attardons pas sur l'origine du paramètre db. Dans un peu de temps, nous parlerons des pilotes de base de données, et c'est là que tout sera révélé.

Une fonction légèrement plus intéressante qui crée une table, insère un enregistrement, interroge l'enregistrement, crée plus d'enregistrements, interroge toutes les lignes et supprime finalement la table est affichée ici. Ce code se trouve dans le fichier oracle-database-client-app.go du référentiel de code.

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)
}
}

Ce code est de nature très fonctionnelle. Outre les instructions SQL, il n'existe pas de détails d'implémentation propres à la base de données. La moitié du code semble traiter les erreurs. Il ne devrait pas être trop difficile de comprendre comment ce code manipule la base de données, sauf qu'il n'y a pas encore de base de données avec laquelle travailler, et donc pas de pilote pour établir la connexion et gérer la communication. Pour y remédier, nous allons d'abord exécuter une base de données locale, puis ajouter un pilote à la base de données dans l'application Go.

Exécuter Oracle Database local

Il existe de nombreuses façons de faire fonctionner une base de données Oracle Database locale. Le moyen le plus simple que j'ai trouvé utilise une image de conteneur Docker qui me permet d'exécuter une base de données locale avec une déclaration très simple et directe :

docker run -d -p 1521:1521 -e ORACLE_PASSWORD=TheSuperSecret1509! gvenzl/oracle-xe

Cette opération exécute une instance Oracle Database XE 21c (au moins, c'est ce qu'elle fait au moment de l'écriture, lorsque 21c est la dernière image de conteneur disponible) et définit les mots de passe pour SYS et SYSTEM sur la valeur indiquée. La base de données est disponible sur le port 1521 sur localhost.

Gerald Venzl d'Oracle gère une série d'images de conteneur (Docker) qui exécutent une version mince d'Oracle Database, l'édition XE, gratuite (jusqu'à 20 Go de données et utilisant un maximum de 2 threads de processeur et 2 Go de RAM). Il décrit ces images et explique comment les utiliser dans un article intitulé Présentation des images gvenzl/oracle-XE : Oracle Database XE Docker.

Pour vérifier que l'instance Oracle Database locale est en fonctionnement, procédez comme suit :

  1. Recherchez l'identificateur de conteneur avec docker ps | grep gvenzl. Ouvrez ensuite un shell Bash dans le conteneur :
    ```console
    
    docker exec -it <container identifier=""> /bin/bash
    ``` </container>
  2. Connectez-vous à la base de données et exécutez des instructions SQL :
    ```console
    
    sqlplus system/TheSuperSecret1509! as sysdba
    ```
  3. Créez un utilisateur (schéma) à utiliser dans les sections suivantes, par exemple un utilisateur de démonstration innocent :
    ```sql
    
    create user demo identified by demo default tablespace users temporary tablespace temp 
    /
    grant connect, resource to demo 
    /
    ```

Maintenant, il est temps de se connecter à cette base de données à partir de l'application 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.

Ajouter un pilote pour Oracle Database

Il n'existe aucun pilote Go officiel pour Oracle Database, au moins aucun pilote publié ou approuvé par Oracle. La liste non officielle des pilotes de base de données Go contient quatre entrées pour Oracle Database. Trois nécessitent l'installation des bibliothèques client Oracle, et l'autre non. Commençons par travailler avec ce dernier, appelé go-ora, un pilote pur qui, à lui seul, gère toutes les communications avec la base de données. Les détails sur go-ora sont disponibles sur la page d'accueil de go-ora sur GitHub. Par la suite, nous examinerons également Godror, un pilote qui nécessite l'installation des bibliothèques et celui qui semble le plus important parmi les pilotes Oracle Database pour Go.

Le pilote go-ora peut être ajouté à l'application Go avec :

go get github.com/sijms/go-ora/v2

Le package est téléchargé et une entrée requise est ajoutée au fichier go.mod. Pour moi qui ressemble à ceci :

module oracle-database-client


go 1.16

require (
github.com/sijms/go-ora/v2 v2.4.16 // indirect
)

Dans un nouveau fichier nommé pure-oracle-database-client.go (même si Go ne se soucie pas vraiment du nom) situé dans le même répertoire que le fichier oracle-database-client-app.go, le code suivant gère l'interaction avec l'instance Oracle Database locale via go-ora. Le package de pilote est importé et l'appel à sql.Open, qui fait référence implicitement à oracle, sélectionne go-ora comme pilote de choix.

Le paramètre dbParams se compose d'une correspondance des paramètres de configuration (y compris le nom utilisateur et le mot de passe), de l'hôte et du port de base de données et du nom de service à utiliser pour établir une connexion. La chaîne de connexion est composée à l'aide de ces éléments et utilisée dans l'appel à sql.Open. L'appel ultérieur à db.Ping est la première tentative d'établir réellement des communications avec la base de données. Lorsque cet appel aboutit, nous sommes prêts pour des actions de base de données réelles.

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
}

Connexion et exécution

La base de données est en cours d'exécution et nous disposons d'une fonction qui fonctionne avec un pilote Oracle Database pur. Revenons maintenant à oracle-database-client-app.go et associons-le.

Ajoutez la fonction main dans ce fichier. Il appelle GetSqlDBWithPureDriver pour créer une instance sql.DB à l'aide des détails de connexion de base de données définis dans la correspondance localDB. Modifiez ces valeurs pour les aligner sur la configuration de la base de données. L'appel de fonction définit la variable de base de données avec *sql.DB, qui peut être utilisée pour d'autres opérations SQL.

Une fois toutes les interactions de base de données terminées, la connexion doit être fermée pour libérer les ressources. Pour vous assurer que cela est fait, le différé dans la fonction main immédiatement après l'appel à GetSqlDBWithPureDriver est ajouté avec l'appel à db.Close(). L'appel à la fonction sqlOperations qui passe db nous amène à la fonction dont nous avons discuté il y a deux sections où la base de données est vraiment interagi.

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)
}

Exécutez l'application à partir de la ligne de commande en utilisant go run *.go. Le résultat se présente comme suit :

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

Utilisation du pilote GoDrOr

Une alternative populaire à go-ora est le Godror du package Go (anciennement appelé goracle, mais renommé en raison de problèmes de marques de commerce - Oracle Corporation ne veut pas que quiconque utilise oracle dans son nom). Ce package fournit également un pilote Oracle Database que Database/SQL peut utiliser lorsqu'une instruction sql.Open est exécutée pour oracle ou godror. Contrairement à go-ora, ce package nécessite l'installation d'une bibliothèque Oracle Instant Client sur le système exécutant l'application Go.

  • Installation de la bibliothèque Oracle Instant Client

    Le pilote GoDrOr utilise l'interface de programmation Oracle Database pour C (ODPI-C). Il s'agit d'une bibliothèque open source de code C, gérée par Oracle Corporation, qui simplifie l'utilisation des fonctionnalités Oracle Call Interface (OCI) communes pour les pilotes d'Oracle Database et les applications utilisateur. Lors de l'utilisation de GoDrOr, nous n'avons pas besoin d'installer ODPI-C ou d'être même au courant de son existence. Toutefois, l'environnement dans lequel s'exécute notre application Go, y compris le pilote, doit contenir les bibliothèques client Oracle.

    Le client Oracle le plus simple est le client Oracle Instant Client gratuit (reportez-vous à la page de présentation d'Oracle Instant Client). Seul le pack "Basic" ou "Basic Light" est requis. Les bibliothèques Oracle Client sont également disponibles dans toutes les installations Oracle Database ou Oracle Client. Des instructions d'installation détaillées pour Linux sont disponibles dans la Documentation Oracle Database pour la version 21c - Guide d'installation de Database Client pour Linux - Installation d'Oracle Instant Client.

    ODPI-C charge dynamiquement les bibliothèques client Oracle disponibles lors de l'exécution. Les bibliothèques client Oracle sont recherchées dans le même répertoire que la bibliothèque ODPI-C (ou binaire d'application). S'ils ne sont pas trouvés, ils sont recherchés dans le chemin de recherche standard du système d'exploitation, par exemple PATH sous Windows ou LD_LIBRARY_PATH sous Linux. Enfin, sur des plateformes autres que Windows, $ORACLE_HOME/lib est également recherché. Pour plus de détails sur la recherche des bibliothèques client Oracle par ODPI-C, consultez ODIP-C GitHub Home - ODPI-C Installation.

  • Modification de l'application Go pour qu'elle fonctionne avec GoDrOr

    Les changements que nous devons apporter à l'application afin de passer de go-ora à godror sont minimes.

    Tout d'abord, le pilote godror est ajouté à l'application Go avec :

    github.com/godror/godror

    Le package est téléchargé et une entrée requise est ajoutée au fichier go.mod.

    Ensuite, créez un fichier nommé godror-based-oracle-database-client.go dans le même répertoire d'application, qui est très similaire à pur-oracle-database-client.go, qui contient les détails de connexion via le pilote go-ora.

    Le contenu de ce nouveau fichier :

    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
    }

    L'importation pour le paquet godror est différente de l'importation de go-ora. Le reste du code est exactement le même qu'auparavant.

    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.

    Enfin, pour que l'application cesse d'utiliser go-ora et commence à utiliser godror, il suffit de commenter ou de supprimer une ligne et d'en ajouter une autre dans la fonction main, en appelant GetSqlDBWithGoDrOrDriver :

    func main() {
    
    //db := GetSqlDBWithPureDriver(localDB)
    db := GetSqlDBWithGoDrOrDriver(localDB)

    Exécutez à nouveau l'application avec go run *.go et vous trouverez le même résultat qu'auparavant. Le fait qu'Oracle Instant Client soit impliqué maintenant n'est pas perceptible. Le comportement est apparemment inchangé, même s'il pourrait y avoir des différences non fonctionnelles telles que les performances de certaines opérations.

Gestion des transactions de base de données

Ce qui n'est pas immédiatement évident lors de notre discussion précédente, c'est que nous n'avons jamais réellement engagé de données dans la base de données. Toutes les actions SQL ont eu lieu dans une seule session de base de données. Les deux opérations LDD qui ont créé et supprimé la table ont implicitement validé la transaction, mais aucune des instructions d'insertion n'a été validée. Certaines bases de données disposent d'un paramètre de validation automatique (même par défaut) qui transforme chaque opération LMD en une transaction validée automatiquement. Ce n'est pas le cas avec Oracle Database. Pour valider les modifications apportées aux enregistrements de base de données, ces modifications doivent être explicitement validées ou annulées au cas où leurs effets durables ne seraient pas souhaitables. Dans notre application Go, nous pouvons travailler explicitement avec les transactions de base de données : en commençant une transaction (sql.Tx) sur une base de données, en exécutant des instructions DML sur cette transaction, puis en validant ou en annulant (rollback) la transaction. Par exemple :

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 Application parlant à OCI Autonomous Database

Faire en sorte qu'une application Go communique avec une base de données Oracle Database locale (ou traditionnellement connectée). Les bases de données configurées pour les communications cryptées à partir de clients qui utilisent Oracle Wallet, telles que les instances Oracle Autonomous Database sur OCI, ne sont plus difficiles à interagir. Nous devons étendre notre code pour utiliser le fichier Oracle Wallet. Bien sûr, nous devons exécuter une instance Autonomous Database et acquérir le portefeuille Oracle Wallet associé.

Exécution gratuite d'Autonomous Database sur OCI

L'exécution d'une instance Autonomous Database est presque plus simple que l'exécution d'une base de données locale. Une instance ATP peut être créée de plusieurs manières (y compris via l'interface de ligne de commande OCI et Terraform), mais la méthode la plus simple pour votre première fois est probablement via la console de navigateur 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.

Créons votre instance ATP toujours gratuite :

Tapez aut dans la zone de recherche de la console, accédez à *Fonctionnalités Autonomous Database*, cliquez sur le bouton Créer une base de données Autonomous Database.


way-to-go-on-oci-article-4-nav-autonomous-db

Dans le formulaire de création, indiquez un nom d'affichage (peut-être go-on-oci-db) et un nom de base de données, sélectionnez Traitement des transactions comme type de charge globale, basculez l'option Toujours gratuit sur Actif, indiquez un mot de passe pour ADMIN (et rappelez-vous bien), acceptez l'accès sécurisé au type d'accès réseau à partir de n'importe quel endroit et assurez-vous que la case Exiger l'authentification TLS mutuelle (mTLS) est cochée.


create-autonomous-db

Après avoir appuyé sur le bouton Create Autonomous Database (Créer une base de données autonome) pour créer la base de données, le statut de provisionnement est présenté :


provisioningatp

La disponibilité de la base de données prend moins d'une minute.

Télécharger le portefeuille de base de données avec les détails de connexion

Nous avons besoin du portefeuille de base de données contenant les certificats SSL requis pour l'interaction mTLS. Téléchargez le portefeuille de l'instance ATP. Cliquez d'abord sur le bouton Connexion de base de données sur la page ATP de la console OCI, puis sur Télécharger le portefeuille.


téléchargerdbwallet

Indiquez un mot de passe pour le portefeuille. Ce mot de passe peut être nécessaire pour la lecture ultérieure du portefeuille. Accrochez-vous également à ce mot de passe, même si je n'ai pas eu besoin de ce mot de passe pour les étapes décrites dans cet article.

Enregistrez le fichier ZIP. Nous l'utiliserons bientôt.


downloadwallet2

Création d'un compte utilisateur de démonstration dans Autonomous Database

Vous pouvez créer un compte utilisateur de démonstration dans la base de données autonome. Pour ce faire, procédez comme suit :

  1. Dans la page de détails ATP, cliquez sur le bouton Database Actions. Connectez-vous en tant qu'administrateur utilisateur et utilisez le mot de passe que vous avez utilisé lors de la configuration du DAV.

  2. Dans la fenêtre de lancement de Database Actions, cliquez sur la mosaïque SQL. La feuille de calcul SQL est ouverte.

  3. sqldevelopper
  4. Collez les instructions ci-dessous dans la feuille de calcul et l'icône permettant d'exécuter le script (ou utilisez le bouton F5 du clavier). Ces instructions créent un utilisateur (schéma) avec lequel travailler dans les sections suivantes, comme nous l'avons fait dans la base de données locale :
    create user demo identified by thePassword1 default tablespace users temporary tablespace temp
    
    /
    grant connect, resource to demo 
    /
    ALTER USER DEMO QUOTA UNLIMITED ON DATA
    /

Modifier l'application Go avec les détails de connexion ATP et Oracle Wallet

Lorsque l'instance Oracle Database avec laquelle je souhaite interagir doit être connectée à l'aide d'un portefeuille Oracle Wallet, je dois transmettre l'emplacement du système de fichiers d'Oracle Wallet au pilote. Plus précisément, je dois indiquer le chemin du répertoire contenant le fichier cwallet.sso qui fait partie du portefeuille. Le portefeuille est généralement fourni dans une archive ZIP. Cette archive doit être extraite (ou au moins ce fichier doit l'être) et le chemin d'accès au répertoire contenant le fichier correspond à ce qui sera appelé walletLocation. A ce stade, extrayez cwallet.sso du fichier ZIP de portefeuille et déplacez ce fichier vers un emplacement accessible à partir de l'application Go. Il peut même se trouver dans le même répertoire que l'application Go elle-même. Ce n'est pas la meilleure pratique pour les applications de qualité de production, mais aux fins de cet article, il suffira.

Les détails de connexion de la base de données autonome qui doivent être fournis sont constitués du même ensemble d'éléments que celui utilisé précédemment pour la base de données locale. Le nom du service de base de données se trouve dans le fichier tnsnames.ora du fichier ZIP de portefeuille ou sur la page Connexion à la base de données ATP de la console OCI sous la forme service_name. La valeur de la propriété de serveur est disponible en tant qu'hôte dans ces emplacements.

Lorsque les propriétés sont collectées, la définition de correspondance suivante peut être ajoutée dans le fichier oracle-database-client-app.go, sous localDB :

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
}

Interaction Go avec Autonomous Database à l'aide de la fonction Go-ora de pilote

La configuration du pilote go-ora doit être étendue un peu pour inclure l'emplacement du portefeuille dans la chaîne de connexion et configurer le protocole de communication sécurisé.

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)
...

Pour exécuter l'application sur Autonomous Database et effectuer ses acrobaties TEMP_TABLE dans le cloud, nous devons modifier légèrement la fonction principale :

func main() {

db := GetSqlDBWithPureDriver(autonomousDB)
//db := GetSqlDBWithGoDrOrDriver(localDB)
...

Autrement dit, remplacez la référence localDB dans l'appel à GetSqlDBWithPureDriver par autonomousDB.

Exécutez à nouveau l'application avec go run *.go. Les résultats seront exactement les mêmes qu'auparavant pour la base de données locale, mais ils prendront probablement un peu plus de temps à être produits car la latence est désormais introduite dans chacune des interactions de base de données.

Interaction Go avec Autonomous Database à l'aide de Driver godror

Le pilote Godror utilise une configuration légèrement différente pour utiliser un portefeuille Oracle Wallet par rapport à go-ora. La fonction GetSqlDBWithGoDrOrDriver du fichier godror-based-oracle-database-client.go est étendue pour gérer ce cas :

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()
...

Pour exécuter l'application avec le pilote godror sur Autonomous Database et effectuer ses acrobaties TEMP_TABLE dans le cloud, nous devons modifier légèrement la fonction principale :

func main() {

//db := GetSqlDBWithPureDriver(autonomousDB)
db := GetSqlDBWithGoDrOrDriver(autonomousDB)
...

Exécutez à nouveau l'application avec go run *.go. Les résultats seront à nouveau exactement les mêmes qu'avec le pilote go-ora, mais il semble (du moins dans mon environnement) que les actions à travers go-ora sont sensiblement plus rapides que les mêmes actions à travers godror.

Déployer une application Go parlant à Autonomous Database vers OCI

Le référentiel de code contient une application appelée service de données, dans le répertoire /applications/data-service. Cette application est une extension de l'application myserver avec laquelle nous avons travaillé dans les articles un et deux de cette série. L'application gère toujours les demandes HTTP comme elle l'a fait auparavant et implémente également une API de données simple. A l'aide des demandes PUT, POST et DELETE, l'application peut être utilisée pour créer, mettre à jour et supprimer des enregistrements de personne d'une table appelée PEOPLE dans une base de données Oracle Database. Les demandes GET permettent de récupérer les détails actuels d'une personne.

Nous allons d'abord examiner brièvement les éléments intéressants de l'application, puis l'exécuter localement. L'étape suivante consiste à exécuter cette application sur OCI dans une instance Compute. Vous constaterez qu'il n'y a rien de très spécial à propos d'une application qui dispose d'une interaction Autonomous Database en matière de déploiement sur OCI. Ou, du moins pas avant le prochain versement de cette série où nous utiliserons OCI Key Vault pour conserver en toute sécurité les détails Oracle Wallet que, grâce à l'autorisation basée sur le principal d'instance, l'application peut extraire lors de l'exécution. Toutefois, pour l'instant, le "wallet" est inclus dans le référentiel de code source et traité dans les pipelines de build et de déploiement. Ce n'est pas une bonne pratique et elle sera corrigée dans le prochain article.

Une fois l'application déployée, nous vérifions si nous pouvons y accéder directement avec un accès direct à l'instance de calcul. Pour appliquer une bonne pratique concernant (pas) l'exposition publique directe des services, nous étendons ensuite la passerelle d'API avec un autre routage menant au service de données, et en particulier ses fonctionnalités basées sur la base de données.

La situation finale que nous avons atteinte sur OCI à la fin de cette section se présente comme suit :


devops-oci-vm

Examiner le service de données et configurer pour votre instance ATP

Le fichier data-server.go est nouveau dans l'application. Il contient toute la logique permettant d'interagir avec la base de données et de gérer toute demande HTTP envoyée à l'application dans les données de chemin : DATA_PATH. L'enregistrement dans la fonction principale de la fonction DataHandler intègre les fonctionnalités de gestion des données.

http.HandleFunc(DATA_PATH, DataHandler)

La fonction principale est également étendue avec les étapes d'initialisation suivantes :

func main() {

db := GetSqlDBWithGoDrOrDriver(autonomousDB)
defer func() {
  err := db.Close()
  if err != nil {
      fmt.Println("Can't close connection: ", err)
  }
}()
InitializeDataServer(db)
...

Au démarrage de l'application my-server, une connexion de base de données est créée et le serveur de données est configuré. L'application utilise le pilote Godror. Nous utilisons le fait que l'instance Compute qui est la cible de déploiement a été créée (dans la première partie de la série) sur l'image Oracle Linux Cloud Developer et qu'Oracle Instant Client est préinstallé.

Il suffit d'ajouter l'application pour l'exécuter :

  1. Copiez le fichier cwallet.sso dans le répertoire racine de l'application.
  2. Définissez les détails de connexion à Autonomous Database dans data-server.go

Vous pouvez ensuite exécuter l'application localement, en utilisant

go run *.go

L'application démarre et rend compte de ses tâches.

Dans une fenêtre de terminal distincte, vous utilisez des instructions curl pour interagir avec l'API Person. Ces demandes HTTP entraîneront la création de deux enregistrements - pour Mickey Mouse et Bugs Bunny. L'enregistrement de Mickey est mis à jour une fois. Les deux enregistrements sont extraits une fois. Ensuite, les deux sont supprimés. La demande GET finale ne renvoie aucune donnée.

N'hésitez pas à ajouter des demandes curl ou à ne pas tout exécuter. Vous pouvez, par exemple, vérifier dans SQL Worksheet si l'API Person a créé les enregistrements de base de données attendus.


feuille de calcul SQL

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

Validation, transmission et création menant au déploiement et à l'exécution

Cette variante de l'application myserver est prête à être utilisée et le code se trouve déjà dans le référentiel de code OCI DevOps, car tout le code du référentiel source de l'article sur GitHub a été validé dans le référentiel de code OCI dans le deuxième article de cette série. Cependant, vous avez ajouté le fichier cwallet.sso (Oracle Wallet pour votre instance Autonomous Database) et vous avez mis à jour les données du fichier server.go pour fournir les détails de connexion à la base de données. Avant de pouvoir utiliser le pipeline de build sur OCI pour créer et déployer ensuite l'application, vous devez d'abord ajouter le nouveau fichier, valider le fichier modifié et le fichier ajouté, puis propager les modifications vers le référentiel de code OCI DevOps.

Après ces actions git add, commit et push, le référentiel de code go-on-oci-repo doit contenir votre cwallet.sso et les données-service.go que vous avez modifiées.

Vous pouvez désormais réutiliser le serveur de build de pipeline de build qui a été configuré à l'article deux lorsque nous avons discuté des pipelines de build OCI DevOps pour la première fois. Cependant, le pipeline actuel attend le fichier de spécification de build à l'emplacement par défaut, ce qui ne sera pas le cas pour l'application myserver modifiée.

  1. Ouvrez la page de détails du build-myserver de pipeline de build dans la console OCI. Ouvrez les détails de la phase de build géré. Cliquez sur Modifier.

  2. buildpsec

  3. Remplacez la valeur du champ Chemin du fichier de spécification de build par /applications/data-service/build_spec.yaml, la spécification de build modifiée pour créer la version étendue de myserver. Cliquez sur Enregistrer.

  4. pipeline

  5. Démarrez une exécution de build. Définissez une nouvelle version pour le paramètre MYSERVER_VERSION si vous le souhaitez.

Le pipeline produira un nouvel artefact : un fichier ZIP contenant l'exécutable créé à partir des sources Go dans le répertoire /applications/data-service et contenant le fichier de portefeuille et le sous-répertoire du site Web. Le pipeline déclenche le pipeline de déploiement qui amène l'artefact vers l'instance Compute, copie l'application dans le répertoire /tmp/yourserver et exécute l'application. Il commence à écouter les demandes HTTP sur le port indiqué par le paramètre de pipeline de déploiement HTTP_SERVER_PORT (ou sur 8080 si le paramètre n'est pas défini).

Vous pouvez accéder à l'API Person sur l'adresse IP publique de la machine virtuelle, si celle-ci est toujours exposée :

curl -X "GET"  <public ip="" for="" compute="" instance="">:8095/data?name=Mickey+Mouse

 </public>

Vous pouvez créer un routage sur la passerelle d'API pour fournir un accès public approprié à l'API de personne. Veillez à ajouter toutes les méthodes gérées par l'API à la définition de routage.


pipeline

Lorsque le déploiement est mis à jour, l'API Person est disponible à l'adresse https :// /my-api/person ?name=Mickey+Mouse.


instance de calcul

Curl et d'autres outils HTTP comme Postman peuvent être utilisés pour interagir avec l'API, en utilisant toutes les méthodes pour créer, mettre à jour, extraire et supprimer des enregistrements de personne.


navigateur

Application Go sur OCI interagissant avec Autonomous Database et le service Object Storage

La dernière étape de cet article combine l'interaction avec le service OCI Object Storage (introduit dans l'article précédent) avec les opérations sur une instance Autonomous Database dans une seule application Go qui est d'abord exécutée localement, puis déployée et exécutée sur une instance de calcul dans OCI et exposée via API Gateway. La fonctionnalité fournie est l'envoi d'une demande HTTP GET avec les noms d'un objet et d'un bucket sur Object Storage. L'objet doit être un fichier JSON contenant des données sur les personnes au format suivant :

[

{
  "name": "Jasper",
  "age": 19,
  "comment": "Haute Couture"
},
{
  "name": "James",
  "age": 3,
  "comment": "Golden retriever"
}
]

Le fichier sera lu et les enregistrements seront créés dans la table PEOPLE dans Autonomous Database pour chacune des entrées JSON.

Tout ce que vous devez ajouter à l'application pour exécuter :

  1. Copiez le fichier cwallet.sso dans le répertoire racine de l'application.
  2. Définissez les détails de connexion à Autonomous Database dans data-server.go
  3. Modifier my-server.go : définissez la valeur correcte pour compartmentOCID
  4. Téléchargez le site Web de fichier/sample-persons.json vers un bucket sur le service Object Storage (vous pouvez modifier le fichier ou télécharger un autre fichier avec un contenu similaire)

Vous pouvez ensuite exécuter l'application localement, en utilisant

go run *.go

L'application démarre et rend compte de ses tâches.

Dans une fenêtre de terminal distincte, vous utilisez des instructions curl pour interagir avec la nouvelle API du processeur de fichiers Persons. Une demande HTTP doit transmettre le nom du bucket et de l'objet contenant les données JSON à traiter. Le service extrait le fichier, analyse son contenu et crée ou met à jour les enregistrements de la table PEOPLE dans la base de données autonome.

curl "localhost:8080/people?objectName=sample-persons.json&bucketName=the-bucket"

A l'aide d'un appel à l'API de données, vous pouvez inspecter les enregistrements de données :

curl localhost:8080/data?name=Martha

Vous pouvez également effectuer la même opération dans SQL Developer Worksheet :


traitement personnalisé

La fonction PeopleJSONProcessor, qui gère la création (ou la mise à jour) d'enregistrements dans la table PEOPLE, peut vous intéresser. Il utilise une approche LMD en masse propre à Oracle (syntaxe prise en charge par le pilote Godror), dans laquelle des tableaux de valeurs pour chacun des paramètres de liaison sont transmis et tous les enregistrements sont créés dans une instruction LMD unique. Assez efficace.

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)
}

Maintenant, amenons cette application vers OCI, vers l'instance Compute que nous avons également utilisée dans la section précédente. Certaines étapes sont nécessaires pour la préparation :

  1. Modifier l'objet de fichier : processor.go : remplacez la valeur de const RUN_WITH_INSTANCE_PRINCIPAL_AUTHENTICATION par False (cet indicateur est False lors de l'exécution locale et True lors de l'exécution sur une instance Compute dans OCI où l'authentification et l'autorisation du principal d'instance sont utilisées)
  2. Actions Git : ajoutez cwallet.sso et validez ce nouveau fichier avec les fichiers modifiés my-server.go, object-processor.go et data-service.go ; propagez la validation vers le référentiel de code OCI
  3. Assurez-vous qu'il existe une stratégie IAM permettant au groupe dynamique go-on-oci-instances de lire les objets dans le compartiment, ce qui permet à l'application exécutée sur la machine virtuelle d'appeler Object Storage Service pour lire le fichier JSON avec les enregistrements de personne. L'instruction de stratégie peut se lire comme suit : autoriser dynamic-group go-on-oci-instances à lire des objets dans le compartiment go-on-oci

Après ces actions git add, commit et push, le référentiel de code go-on-oci-repo doit contenir votre cwallet.sso et les données-service.go que vous avez modifiées.

Vous pouvez désormais réutiliser le serveur de build de pipeline de build que nous avons utilisé précédemment. Comme nous l'avons fait précédemment, nous devons mettre à jour la référence au fichier de spécification de build.

  1. Ouvrez la page de détails du build de pipeline - Serveur myserver dans la console OCI
  2. Ouvrir les détails de la phase de build géré
  3. Cliquez sur Modifier.
  4. Remplacez la valeur du champ Chemin du fichier de spécification de build par /applications/people-file-processor/build_spec.yaml, la spécification de build modifiée pour créer la version étendue de myserver
  5. Cliquez sur Save.

spécification de build

Démarrez une exécution de build. Définissez une nouvelle version pour le paramètre MYSERVER_VERSION si vous le souhaitez.

Le pipeline produira un nouvel artefact : un fichier ZIP contenant l'exécutable créé à partir des sources Go dans le répertoire /applications/people-file-processor et contenant le fichier de portefeuille et le sous-répertoire du site Web. Le pipeline déclenche le pipeline de déploiement qui amène l'artefact vers l'instance Compute, copie l'application dans le répertoire /tmp/yourserver et exécute l'application. Il commence à écouter les demandes HTTP sur le port indiqué par le paramètre de pipeline de déploiement HTTP_SERVER_PORT (ou sur 8080 si le paramètre n'est pas défini).

Vous pouvez accéder à l'API sur l'adresse IP publique de la machine virtuelle, si elle est encore exposée. Il est préférable d'ajouter une route sur la passerelle d'API pour exposer l'accès au processeur de fichiers du personnel :

  1. Accéder aux détails de la passerelle API
  2. Ouvrir l'onglet Déploiements
  3. Cliquez sur Modifier.
  4. Ouvrez la deuxième étape pour Routes et ajoutez une nouvelle route.

Définissez le chemin en tant que /personnel-file-handler. La méthode GET doit être prise en charge. Le type de routage est HTTP. L'URL est : http ://<Adresse IP publique pour l'instance de calcul> :8095/people. Vérifiez la valeur de HTTP_SERVER_PORT sur le pipeline de déploiement deploy-myserver-on-go-app-vm. Si elle n'est pas définie sur 8095, modifiez la valeur de l'URL afin d'utiliser le numéro de port approprié pour l'application.


processeur

Appuyez sur Next, puis sur Save changes. L'actualisation du déploiement de la passerelle d'API prendra un moment. Une fois que c'est le cas, le service qui lit un fichier à partir d'un bucket Object Storage traite le contenu JSON et crée des enregistrements dans la table PEOPLE dans l'instance Autonomous Database pour les entrées de ce fichier peut être déclenché avec une simple demande HTTP GET vers https ://<public endpoind of API Gateway>/my-api/personnel-file-handler ?objectName=sample-persons.json&bucketName=the-bucket.

L'effet de l'appel peut être inspecté via l'API de la personne qui lit les enregistrements de cette même table dans la même base de données : https ://<public endpoind of API Gateway>/my-api/person ?name=Jasper.

L'image de bout en bout de ce qui est maintenant déployé sur OCI est présentée dans la figure suivante.


version2

Ce qui n'est pas montré dans l'image et est important de noter :

  • le fichier Oracle Wallet déployé avec l'application (dans l'artefact créé à partir de la source dans le référentiel de code)
  • référence codée en dur au compartiment dans l'application
  • stratégie qui autorise l'instance de calcul à lire des objets

Dans l'article suivant, nous examinons OCI Key Vault, un service qui offre un bien meilleur moyen de stocker Oracle Wallet et de le mettre à la disposition de l'application lors du déploiement (ou même de l'exécution).

Conclusion

Cet article explique comment interagir avec une base de données Oracle Database à partir d'applications Go, qu'elles soient traditionnelles ou autonomes. Nous avons vu comment une connexion d'une application Go à une base de données Oracle Database locale (ainsi qu'à une base de données Autonomous Database) est établie à l'aide d'un pilote et éventuellement de bibliothèques de prise en charge, et comment les opérations DDL et DML SQL peuvent être effectuées avec ces bases de données sans passer par l'application Go. L'utilisation d'un portefeuille Oracle Wallet pour la gestion appropriée des informations d'identification et de connexion (autonomes) à la base de données a été étudiée. Une application exécutée sur une instance de calcul OCI, interagissant via le kit SDK Go pour OCI avec Object Storage Service et manipulant Autonomous Database - déployé automatiquement via OCI DevOps - a fourni la finale de l'article.

Le cinquième et dernier article de cette série ajoute deux autres services OCI avec lesquels les applications Go peuvent interagir : OCI Streaming - un broker de messages de diffusion en continu à volume élevé qui permet des interactions découplées entre différents microservices et d'autres composants - et OCI Key Vault pour la gestion des clés secrètes telles qu'Oracle Wallet avec des informations d'identification de base de données. Cet article présente également un troisième type de plate-forme d'application en regard de la machine virtuelle et de la fonction sans serveur, sous la forme de l'initiateur OCI Kubernetes géré (OKE), et montre comment DevOps Deployment Pipelines peut déployer nos applications Go vers OKE de manière automatisée.

Cette page a été traduite automatiquement.

Oracle Chatbot
Disconnected