Go 및 Oracle Cloud Infrastructure(OCI)에 대한 5부 시리즈 중 네 번째 부분입니다. 이 시리즈에서는 Oracle Cloud Infrastructure의 컴퓨트 인스턴스(VM), Kubernetes에서 컨테이너화 또는 서버리스 함수로 Go 애플리케이션을 생성하고 실행하는 방법에 대해 설명합니다. 이 문서는 OCI DevOps를 사용하여 이러한 Go 애플리케이션의 구축 및 배포를 자동화하는 방법을 보여줍니다. 중요한 주제는 Go 애플리케이션의 OCI 서비스(OCI에서 실행되는 서비스 및 다른 곳에서 실행되는 Go 코드 모두)를 사용하는 방법입니다. OCI 서비스에는 Object Storage, Streaming, Key Vault 및 Autonomous Database가 포함됩니다.
이 기사와 함께 따르려면 독자는 Go 응용 프로그램을 만드는 방법에 대한 최소한의 기본 지식을 가지고 있어야합니다. 독자가 자신의 Go 개발 환경에 액세스할 수 있다고 가정합니다. 예제와 스크린샷 중 일부는 VS Code를 개발 툴로 구체적으로 언급할 것입니다. 그러나 다른 편집자 및 IDE도 사용할 수 있습니다. 이 문서에 제시된 Go 코드는 명확성을 극대화하고 종속성을 최소화하기 위해 가장 간단한 형태의 여러 메커니즘을 보여줍니다. 독자는 의미 있는 기능이나 생산 준비가 완료된 코드를 기대해서는 안됩니다.
이 시리즈는 OCI로 전환하는 방법을 설명합니다. 예제를 시도하려면 독자가 해당 문서에 설명된 OCI 리소스를 생성할 수 있는 권한이 있는 OCI 테넌시에 액세스할 수 있어야 합니다. 사용되는 대부분의 리소스는 Aways Free Tier(컴퓨트 인스턴스, VCN, Autonomous Database, 오브젝트 스토리지, 로깅, 리소스 관리자)에서 사용할 수 있거나 제한된 월별 사용량(Functions, API Gateway, Streaming, Vault, DevOps)에 대해 무료 할당 계층이 있습니다.
이 시리즈의 첫 번째 부분에서는 Oracle Linux Cloud Developer 이미지를 기반으로 한 컴퓨트 인스턴스의 프로비저닝을 설명하고, 인바운드 및 아웃바운드 네트워크 작업을 위해 인스턴스를 열고, HTTP 요청을 제공하는 Go 애플리케이션을 생성 및 실행하고, 애플리케이션에서 생성한 로깅을 OCI 로깅에 연결하는 방법에 대해 설명합니다. 2부에서는 소프트웨어 엔지니어링, OCI DevOps 서비스를 통한 애플리케이션 구축 및 배포 자동화에 대해 다룹니다. 이 서비스는 Go 소스 코드를 저장하고, 애플리케이션 실행 파일을 빌드하여 배치 가능한 아티팩트로 저장하고, 해당 아티팩트를 컴퓨트 인스턴스에 배치하는 데 사용됩니다. 또한 이 문서에서는 OCI API 게이트웨이를 통해 애플리케이션에 대한 HTTP 엔드포인트를 노출하는 방법을 보여줍니다. 3부에서는 Go에서 서버리스 함수를 생성하여 OCI에 배포하는 방법을 보여줍니다. OCI용 Go SDK가 도입되었습니다. 먼저 로컬, 독립형 Go 애플리케이션을 위한 것이고, 이어서 기능에서 사용하기 위해 리소스 주체 인증을 활용합니다. 이 SDK는 OCI Object Storage 서비스와 상호 작용하여 버킷을 생성하고 파일을 쓰고 읽는 데 사용됩니다.
지금 읽고 있는 4부에서는 Go 애플리케이션과 Oracle Database 간의 상호 작용에 대해 설명합니다. 이는 로컬 또는 온프레미스 데이터베이스, 일부 클라우드 공급업체의 IaaS 인스턴스에서 실행되는 데이터베이스 또는 OCI Autonomous Database일 수 있습니다. Oracle Database용 드라이버와 함께 표준 Go 데이터베이스/SQL 패키지를 사용하고 필요한 구성 세부 정보를 드라이버에 제공하면 Go에서 Oracle Database를 활용하는 것이 매우 간단합니다. 2부에 설명된 Go 애플리케이션 myserver는 OCI의 Autonomous Database 인스턴스 및 OCI Object Storage 서비스와 상호 작용할 수 있도록 확장되었습니다. 애플리케이션은 OCI용 Go SDK를 사용하여 Object Storage의 버킷에서 파일을 읽고 제거한 후 해당 콘텐츠를 기반으로 Autonomous Database에 데이터베이스 레코드를 생성합니다.
Go 언어는 내장된 관계형 데이터베이스와의 SQL 상호 작용을 지원합니다. 표준 패키지 데이터베이스/SQL에는 데이터베이스에 연결, 트랜잭션 실행, 진행 중인 작업 취소 등을 위한 유형 및 함수가 포함되어 있습니다. 이 동일한 패키지를 MongoDB 및 Couchbase와 같은 일부 NoSQL 데이터베이스에서 동일한 방식으로 작업하는 데 사용할 수 있습니다.
이 패키지를 통해 데이터베이스와 상호 작용하는 Go 응용 프로그램에는 특정 데이터베이스 제품에 대한 기술적 구현 세부 사항이 없어도 됩니다. 이러한 세부 정보는 일반적으로 해당 데이터베이스의 드라이버에 구현됩니다. 응용 프로그램은 연결에 필요한 데이터베이스 드라이버를 임포트하고 표준 패키지 데이터베이스/SQL에 사용할 드라이버와 데이터베이스에 대한 연결 세부 정보를 알려줍니다. 특정 데이터베이스 기술에 관계없이 데이터베이스와의 상호 작용은 대부분 동일합니다. 레코드는 SQL DML 문을 통해 생성, 갱신 및 삭제되고 레코드는 SQL query를 통해 검색됩니다. 전체 프로세스는 데이터베이스마다 동일하지만 정확한 SQL 방언은 다를 수 있습니다. 이것은 다른 데이터베이스 제품 간에 Go 응용 프로그램을 쉽게 이동하기 위한 유일한 실제 장애물일 수 있습니다.
이 절에 설명된 코드는 이 문서 시리즈와 함께 제공되는 코드 저장소의 /applications/go-orcl-db 디렉토리에 있습니다.
Go Application, SQL 수행 – DDL, DML 및 Query
Go 응용 프로그램에서 Oracle Database를 사용하는 가장 간단한 방법은 단일 행을 query하는 것입니다. 이에 필요한 코드는 다음과 같습니다. 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) 결과를 로컬 변수로 스캔할 수 있습니다. 이 경우 Oracle 특정 시스템 기록을 사용하는 특정 SQL 문을 제외하고는 매우 간단하고 간단하며 데이터베이스 브랜드 독립적입니다.
이제 db 파라미터의 출처가 어디인지 살펴보겠습니다. 잠시 후 데이터베이스 드라이버에 대해 이야기할 것이고, 모든 것이 공개될 것입니다.
테이블을 생성하고, 레코드를 삽입하고, 레코드를 질의하고, 더 많은 레코드에 대해 생성하고, 모든 행을 질의하고, 마지막으로 테이블을 삭제하는 좀 더 흥미로운 함수가 여기에 표시됩니다. 이 코드는 코드 repository의 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를 작동하고 실행하는 방법에는 여러 가지가 있습니다. 내가 찾은 가장 쉬운 방법은 매우 간단하고 간단한 하나의 명령문으로 로컬 데이터베이스를 실행할 수있는 Docker 컨테이너 이미지를 사용합니다.
docker run -d -p 1521:1521 -e ORACLE_PASSWORD=TheSuperSecret1509! gvenzl/oracle-xe
이 스크립트는 Oracle Database XE 21c instance를 실행하고(적어도 21c가 사용 가능한 최신 컨테이너 이미지인 경우 쓰기 시 수행하는 작업) SYS 및 SYSTEM에 대한 암호를 표시된 값으로 설정합니다. 데이터베이스는 localhost의 포트 1521에서 사용할 수 있습니다.
Oracle의 Gerald Venzl은 무료(최대 20GB의 데이터, 최대 2개의 CPU 스레드 및 2GB RAM)인 슬림형 버전의 Oracle Database를 실행하는 일련의(Docker) 컨테이너 이미지를 유지 관리합니다. Introducing gvenzl/oracle-XE: Oracle Database XE Docker images 문서에서 해당 이미지를 사용하는 방법에 대해 설명합니다.
다음 단계에 따라 로컬 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에 대한 네 개의 항목이 있습니다. 세 개를 사용하려면 Oracle Client 라이브러리를 설치해야 하지만 설치하지 않아도 됩니다. 먼저 데이터베이스와의 모든 통신을 처리하는 순수 드라이버인 go-ora라는 마지막 드라이버를 사용해 보겠습니다. go-ora에 대한 자세한 내용은 GitHub의 go-ora 홈 페이지에서 확인할 수 있습니다. 또한 라이브러리를 설치해야 하는 드라이버이자 Go용 Oracle Database 드라이버 중 가장 눈에 띄는 드라이버인 Godror도 살펴볼 것입니다.
다음과 같이 Go-ora 드라이버를 Go 응용 프로그램에 추가할 수 있습니다.
go get github.com/sijms/go-ora/v2
패키지를 다운로드하고 require 항목을 go.mod 파일에 추가합니다. 이렇게 보이는 나를 위해:
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는 실제로 이름을 신경 쓰지 않음) 다음 코드는 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로 돌아가서 함께 연결해 보겠습니다.
이 파일에 함수 기본을 추가합니다. localDB 맵에 정의된 데이터베이스 접속 세부정보를 사용하여 GetSqlDBWithPureDriver를 호출하여 sql.DB 인스턴스를 생성합니다. 데이터베이스 구성에 맞게 이러한 값을 수정합니다. 함수 호출은 db 변수를 추가 SQL 작업에 사용할 수 있는 *sql.DB로 설정합니다.
모든 데이터베이스 상호 작용이 완료되면 리소스를 해제하기 위해 연결을 닫아야 합니다. 이 작업을 완료하려면 GetSqlDBWithPureDriver에 대한 호출 바로 다음에 오는 함수 main에서 지연이 db.Close()에 대한 호출과 함께 추가됩니다. db를 전달하는 함수 sqlOperations 호출은 데이터베이스가 실제로 상호 작용하는 두 섹션 전에 논의한 기능을 제공합니다.
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 패키지 오류(이전 명칭은 goracle이지만 상표 문제로 인해 이름이 바뀜)입니다. Oracle Corporation은 다른 사람이 자신의 이름으로 oracle을 사용하는 것을 원하지 않습니다. 또한 이 패키지는 oracle 또는 godror에 대해 sql.Open를 수행할 때 데이터베이스/SQL에서 사용할 수 있는 Oracle Database 드라이버를 제공합니다. 이 패키지는 go-ora와 달리 Go 응용 프로그램을 실행하는 시스템에 Oracle Instant Client 라이브러리를 설치해야 합니다.
GoDrOr 드라이버는 ODPI-C(Oracle Database Programming Interface for C)를 사용합니다. Oracle Corporation에서 유지 관리하는 오픈 소스 C 코드 라이브러리로, Oracle Database 드라이버 및 사용자 응용 프로그램에 공통 OCI(Oracle Call Interface) 기능을 간편하게 사용할 수 있습니다. 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 Documentation for Release 21c – Database Client Installation Guide for Linux – Installing Oracle Instant Client에서 확인할 수 있습니다.
ODPI-C는 런타임 시 사용 가능한 Oracle 클라이언트 라이브러리를 동적으로 로드합니다. Oracle 클라이언트 라이브러리는 ODPI-C 라이브러리(또는 응용 프로그램 이진)와 동일한 디렉토리에서 검색됩니다. 찾을 수 없는 경우 표준 운영 체제 검색 경로(예: Windows의 경우 PATH, Linux의 경우 LD_LIBRARY_PATH)에서 검색됩니다. 마지막으로 Windows 이외의 플랫폼에서는 $ORACLE_HOME/lib도 검색됩니다. ODPI-C가 Oracle 클라이언트 라이브러리를 찾을 수 있는지 확인하는 것과 관련된 자세한 내용은 ODIP-C GitHub Home – ODPI-C Installation을 참조하십시오.
Go-ora 사용에서 Godror로 전환하기 위해 응용 프로그램에 대한 변경 사항은 최소입니다.
먼저 다음과 같이 Godror 드라이버가 Go 응용 프로그램에 추가됩니다.
github.com/godror/godror
패키지를 다운로드하고 require 항목을 go.mod 파일에 추가합니다.
그런 다음 동일한 응용 프로그램 디렉토리에 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 사용을 시작하려면 한 행을 주석 처리하거나 제거하고 main 함수에서 다른 행을 추가하여 GetSqlDBWithGoDrOrDriver를 호출하면 됩니다.
func main() {
//db := GetSqlDBWithPureDriver(localDB)
db := GetSqlDBWithGoDrOrDriver(localDB)
go run *.go를 사용하여 응용 프로그램을 다시 실행하면 이전과 동일한 출력을 찾을 수 있습니다. Oracle Instant Client가 현재 관련되어 있다는 사실은 눈에 띄지 않습니다. 특정 작업의 성능과 같이 작동하지 않는 차이가 있을 수 있더라도 동작은 변경되지 않는 것처럼 보입니다.
데이터베이스 트랜잭션 관리
앞서 설명한 내용에서 바로 알 수 있는 것은 실제로 데이터를 데이터베이스에 커밋한 적이 없다는 것입니다. 모든 SQL 작업은 단일 데이터베이스 세션에서 수행되었습니다. 테이블을 생성 및 삭제한 두 개의 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와 통신하는 것은 그다지 어렵지 않았습니다. OCI의 Oracle Autonomous Database 인스턴스와 같이 Oracle Wallet을 사용하는 클라이언트로부터의 암호화된 통신을 위해 구성된 데이터베이스는 더 이상 상호 작용하기 어렵지 않습니다. 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.
항상 무료 ATP 인스턴스를 생성합니다.
콘솔의 검색 상자에 aut를 입력하고 *Autonomous Database Features*로 이동한 후 Create Autonomous Database 버튼을 누릅니다.
생성 폼에서 표시 이름(go-on-oci-db) 및 데이터베이스 이름을 제공하고, 작업 로드 유형으로 Transaction Processing을 선택하고, Always Free 토글을 활성으로 토글하고, ADMIN에 대한 비밀번호를 제공하고, 모든 곳에서 Network Access Type Secure 액세스를 수락하고, Require mutual TLS (mTLS) authentication이 선택되어 있는지 확인합니다.
Create Autonomous Database 버튼을 눌러 데이터베이스를 생성하면 프로비저닝 상태가 표시됩니다.
데이터베이스를 사용할 수 있게 되려면 1분 미만이 걸립니다.
접속 세부정보가 포함된 데이터베이스 전자 지갑 다운로드
mTLS 상호 작용에 필요한 SSL 인증서가 포함된 데이터베이스 전자 지갑이 필요합니다. ATP 인스턴스에 대한 전자 지갑을 다운로드합니다. 먼저 OCI 콘솔의 ATP 페이지에서 DB Connection 버튼을 누른 다음 Download wallet을 누릅니다.
전자 지갑에 대한 비밀번호를 제공합니다. 나중에 전자 지갑을 읽는 데 필요할 수 있습니다. 이 문서에 설명된 단계에 대해 이 비밀번호가 필요하지 않더라도 이 비밀번호도 기다리십시오.
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로 찾을 수 있습니다. 서버 등록 정보의 값은 이러한 위치에서 호스트로 사용할 수 있습니다.
등록 정보가 수집되면 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를 사용하여 응용 프로그램을 다시 실행합니다. 결과는 로컬 데이터베이스에 대해 이전과 정확히 동일하지만 각 데이터베이스 상호 작용에서 현재 대기 시간이 도입되므로 생성 시간이 약간 더 오래 걸릴 수 있습니다.
Driver 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를 통한 동일한 행동보다 훨씬 빠릅니다 (적어도 내 환경에서).
Code Repository는 /applications/data-service 디렉토리에 data-service라는 응용 프로그램을 포함합니다. 이 응용 프로그램은 우리가이 시리즈 중 하나와 두 기사에서 함께 일했던 myserver 응용 프로그램의 확장입니다. 애플리케이션은 이전과 마찬가지로 HTTP 요청을 처리하며 이번에는 단순 데이터 API도 구현합니다. PUT, POST 및 DELETE 요청을 사용하면 응용 프로그램을 사용하여 Oracle Database의 PEOPLE이라는 테이블에서 개인 레코드를 생성, 갱신 및 제거할 수 있습니다. GET 요청을 사용하면 모든 사람의 현재 세부 정보를 검색할 수 있습니다.
먼저 애플리케이션의 흥미로운 요소를 간략하게 살펴본 다음 로컬에서 실행합니다. 다음 단계는 이 애플리케이션을 컴퓨트 인스턴스의 OCI에서 실행하도록 만드는 것입니다. OCI에 배포할 때 Autonomous Database와 상호 작용하는 애플리케이션의 특별한 점은 없습니다. 또는 적어도 이 시리즈의 다음 할부까지는 OCI Key Vault를 사용하여 인스턴스 주체 기반 권한 부여 덕분에 애플리케이션이 런타임 시 검색할 수 있는 Oracle Wallet 세부정보를 안전하게 보관할 수 있습니다. 그러나 지금은 전자 지갑이 소스 코드 저장소에 포함되어 빌드 및 배치 파이프라인에서 처리됩니다. 이것은 좋은 방법이 아니며 다음 기사에서 수정 될 것입니다.
애플리케이션이 배포되면 컴퓨트 인스턴스에 직접 접근하여 애플리케이션에 접근할 수 있는지 확인합니다. 공개적으로 서비스를 직접 노출(아니요)하는 것과 관련하여 모범 사례를 적용하기 위해 오라클은 데이터 서비스, 특히 데이터베이스 기반 기능으로 이어지는 경로를 하나 더 사용하여 API 게이트웨이를 확장합니다.
이 섹션이 끝날 때 OCI에서 최종 상황은 다음과 같습니다.
데이터 서비스 검사 및 ATP 인스턴스 구성
data-server.go 파일은 응용 프로그램의 새 파일입니다. 여기에는 데이터베이스와 상호 작용하고 경로 데이터에 들어오는 응용 프로그램에 대한 HTTP 요청을 처리하는 모든 논리가 포함됩니다(DATA_PATH). 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)
...
my-server 응용 프로그램을 시작할 때 데이터베이스 연결이 만들어지고 데이터 서버가 설정됩니다. 응용 프로그램에서 Godror 드라이버를 사용합니다. 배치 대상인 컴퓨트 인스턴스가 Oracle Linux Cloud Developer 이미지에 생성되고(시리즈 중 일부에서 다시 생성됨) Oracle Instant Client가 사전 설치되어 있다는 사실을 사용합니다.
실행하기 위해 추가해야 하는 모든 응용 프로그램은 다음과 같습니다.
그런 다음 다음을 사용하여 로컬에서 응용 프로그램을 실행할 수 있습니다.
go run *.go
애플리케이션이 시작되고 업무에 대해 보고됩니다.
별도의 터미널 window에서 curl 문을 사용하여 Person API와 상호 작용합니다. 이러한 HTTP 요청으로 인해 Mickey Mouse 및 Bugs Bunny에 대한 두 개의 레코드가 생성됩니다. Mickey의 기록은 한 번 업데이트됩니다. 두 레코드는 한 번만 검색됩니다. 그런 다음 둘 다 삭제됩니다. 최종 GET 요청은 데이터를 반환하지 않습니다.
curl 요청을 추가하거나 모두 실행하지 마십시오. 예를 들어, SQL Worksheet에서 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에 있는 문서 소스 저장소의 모든 코드가 이 시리즈의 두번째 문서에 있는 OCI 코드 저장소에 커밋되었으므로 myserver 애플리케이션의 이 변형을 사용할 준비가 되었으며 코드가 이미 OCI DevOps 코드 저장소에 있습니다. 그러나 cwallet.sso 파일(Autonomous Database 인스턴스용 Oracle Wallet)을 추가했으며 데이터베이스 접속 세부정보를 제공하도록 data-server.go 파일을 업데이트했습니다. OCI에서 빌드 파이프라인을 사용하여 애플리케이션을 빌드하고 배치하려면 먼저 새 파일을 추가하고, 변경된 파일과 추가된 파일을 모두 커밋하고, 변경사항을 OCI DevOps 코드 저장소에 푸시해야 합니다.
이러한 git 추가, 커밋 및 푸시 작업이 완료되면 Code Repository go-on-oci-repo에 cwallet.sso 및 수정한 data-service.go가 포함되어야 합니다.
이제 OCI DevOps 빌드 파이프라인에 대해 처음 논의할 때 기사 2에서 설정된 빌드 파이프라인 build-myserver를 재사용할 수 있습니다. 그러나 현재 파이프라인은 기본 위치에 빌드 사양 파일이 있어야 하며 수정된 myserver 응용 프로그램에 대해서는 이 작업이 수행되지 않습니다.
파이프라인은 /applications/data-service 디렉토리의 Go 소스에서 생성되고 전자 지갑 파일 및 웹 사이트 하위 디렉토리를 포함하는 실행 파일이 있는 zip 파일인 새 아티팩트를 생성합니다. 파이프라인이 배치 파이프라인을 트리거하여 아티팩트를 컴퓨트 인스턴스로 가져오고, 애플리케이션을 /tmp/yourserver 디렉토리에 복사하고, 애플리케이션을 실행합니다. 배치 파이프라인 매개변수 HTTP_SERVER_PORT(또는 매개변수가 설정되지 않은 경우 8080)로 지정된 포트에서 HTTP 요청을 수신하기 시작합니다.
VM에 대한 공용 IP 주소에서 Person API에 액세스할 수 있습니다(아직 노출된 경우).
curl -X "GET" :8095/data?name=Mickey+Mouse
API 게이트웨이에서 경로를 생성하여 개인 API에 대한 적절한 공용 액세스를 제공할 수 있습니다. API가 처리하는 모든 메소드를 경로 정의에 추가해야 합니다.
배포가 업데이트되면 개인 API는 https://
Curl 및 Postman과 같은 기타 HTTP 도구는 모든 방법을 사용하여 개인 레코드를 생성, 업데이트, 검색 및 삭제하는 방식으로 API와 상호 작용하는 데 사용할 수 있습니다.
이 문서의 마지막 단계는 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
애플리케이션이 시작되고 업무에 대해 보고됩니다.
별도의 터미널 window에서 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 Worksheet에서도 동일한 작업을 수행할 수 있습니다.
PEOPLE 테이블에서 레코드 생성(또는 갱신)을 처리하는 PeopleJSONProcessor 함수에 관심이 있을 수 있습니다. Godror 드라이버가 지원하는 구문인 Oracle 고유의 대량 DML 접근 방식을 사용합니다. 여기서는 각 바인드 파라미터에 대한 값 배열이 전달되고 모든 레코드가 단일 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 추가, 커밋 및 푸시 작업이 완료되면 Code Repository go-on-oci-repo에 cwallet.sso 및 수정한 data-service.go가 포함되어야 합니다.
이제 이전에 사용한 빌드 파이프라인 build-myserver를 재사용할 수 있습니다. 이전과 마찬가지로 빌드 사양 파일에 대한 참조를 업데이트해야 합니다.
빌드 실행을 시작합니다. 원하는 경우 MYSERVER_VERSION 매개변수의 새 버전을 설정합니다.
파이프라인은 /applications/people-file-processor 디렉토리의 Go 소스에서 생성되고 전자 지갑 파일 및 웹 사이트 하위 디렉토리를 포함하는 실행 파일이 있는 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 값을 수정합니다.
Next, Save changes를 차례로 누릅니다. API 게이트웨이의 배치를 새로고침하는 데 시간이 걸립니다. Object Storage 버킷에서 파일을 읽고 JSON 콘텐츠를 처리하고 Autonomous Database 인스턴스의 PEOPLE 테이블에 이 파일의 항목에 대한 레코드를 생성하는 서비스는 https://<public endpoind of API Gateway>/my-api/personnel-file-handler?objectName=sample-persons.json&bucketName=the-bucket에 대한 간단한 HTTP GET 요청을 통해 트리거될 수 있습니다.
https://<public endpoind of API Gateway>/my-api/person?name=Jasper와 같이 동일한 데이터베이스의 동일한 테이블에서 레코드를 읽는 개인 API를 통해 호출 결과를 검사할 수 있습니다.
다음 그림은 현재 OCI에 배포된 내용에 대한 종단간 그림을 보여줍니다.
그림에 표시되지 않은 내용은 다음 사항에 유의해야 합니다.
다음 기사에서는 Oracle Wallet을 저장하고 배포 시(또는 런타임까지) 애플리케이션에서 사용할 수 있도록 훨씬 더 나은 방법을 제공하는 서비스인 OCI Key Vault를 살펴봅니다.
이 문서는 Go 애플리케이션에서 Oracle Database와 상호 작용하는 방식(전통적인 방식 또는 자율적인 방식)을 보여줍니다. Go 애플리케이션에서 로컬 Oracle Database 및 Autonomous Database로의 연결이 어떻게 이루어지는지, 드라이버 및 지원 라이브러리를 사용하는 방법, Go 애플리케이션에서 이러한 데이터베이스를 사용하여 DDL 및 DML SQL 작업을 수행하는 방법을 확인했습니다. Oracle Wallet을 사용하여 (자율운영) 데이터베이스 인증서를 적절히 관리하는 방법에 대해 설명했습니다. OCI 컴퓨팅 인스턴스에서 실행되는 애플리케이션으로, OCI용 Go SDK를 통해 Object Storage Service와 상호 작용하고, OCI DevOps를 통해 자동으로 배포되는 Autonomous Database를 조작합니다.
이 시리즈의 다섯 번째 및 마지막 기사에서는 Go 애플리케이션이 상호 작용할 수 있는 두 가지 OCI 서비스를 추가합니다. OCI Streaming은 서로 다른 마이크로서비스 및 기타 구성요소 간의 분리된 상호 작용을 허용하는 대용량 스트리밍 메시지 브로커이며, 데이터베이스 인증서를 사용하여 Oracle Wallet과 같은 암호를 관리하기 위한 OCI Key Vault입니다. 또한 관리형 OCI Kubernetes Enginer(OKE)의 형태로 VM 및 서버리스 기능 옆에 있는 세 번째 유형의 애플리케이션 플랫폼을 소개하고 DevOps 배포 파이프라인이 자동화된 방식으로 Go 애플리케이션을 OKE에 배포하는 방법을 보여줍니다.