Go 및 Oracle Cloud Infrastructure에 대한 5부 시리즈 중 세 번째 할부입니다. 이 시리즈에서는 Go 애플리케이션을 VM(컴퓨트 인스턴스)의 OCI(Oracle Cloud Infrastructure)에서 생성 및 실행하거나, Kubernetes에서 컨테이너화하거나, 서버리스 기능으로 실행하는 방법에 대해 설명합니다. 이 문서는 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 Gateway를 통해 애플리케이션에 대한 HTTP 엔드포인트를 노출하는 방법을 보여줍니다.
이 세 번째 부분은 Go에서 서버리스 함수를 생성하고 OCI에 배포하는 방법을 보여줍니다. OCI용 Go SDK가 도입되었습니다. 먼저 로컬, 독립형 Go 애플리케이션을 위한 것이고, 이어서 기능에서 사용할 수 있도록 리소스 주체 인증을 활용합니다. 이 SDK는 OCI Object Storage 서비스와 상호 작용하여 버킷을 생성하고 파일을 쓰고 읽는 데 사용됩니다.
처음에는 함수가 수동으로 작성되고 배치됩니다. OCI 외부 클라이언트에서 함수를 호출하기 위한 경로가 API 게이트웨이의 배치에 추가됩니다. 그런 다음 컨테이너 이미지 레지스트리의 이미지에서 함수를 배치하기 위한 OCI DevOps 배치 파이프라인이 생성됩니다. 마지막으로 빌드 파이프라인은 코드 저장소에서 소스를 가져와서 컨테이너 이미지를 빌드 및 게시한 다음 엔드투엔드 빌드 및 배치를 위해 배치 파이프라인을 트리거하도록 설정됩니다.
OCI의 서버리스 기능은 오픈 소스 Project Fn의 기술을 기반으로 합니다. 함수의 비즈니스 논리는 즐겨찾는 언어(이 경우 Go)로 작성되며 함수의 수명 주기 및 함수와의 상호 작용을 처리하는 Fn 프레임워크에 내장됩니다. Fn 프레임워크는 로컬 시스템, 모든 클라우드의 VM 또는 온프레미스 등 어디에서나 실행할 수 있습니다. Oracle Cloud Infrastructure는 동일한 기술을 기반으로 하는 서버리스 기능을 위한 완전 관리형 PaaS 서비스 OCI Functions를 제공합니다.
함수는 컨테이너 이미지에 내장됩니다. 이 이미지는 컨테이너 이미지 레지스트리에 푸시됩니다. 함수를 게시하기 위해 이 이미지는 Fn 서버로 전송됩니다. 함수가 호출될 때마다 이미지에서 컨테이너가 시작되고 요청이 처리됩니다. 컨테이너는 호출을 처리한 후 추가 요청을 처리할 준비가 된 핫 상태로 일정 시간 동안 계속 실행됩니다. 동시 요청 수가 증가하면 모든 요청을 처리할 수 있도록 Fn 서버가 동일한 기능에 대한 추가 컨테이너를 시작합니다.
개발자와 응용 프로그램 운영자를위한 기능의 매력은 비즈니스 논리를 실행하는 플랫폼을 설계, 제작 및 관리하는 데 에너지를 쏟을 필요가 없다는 사실입니다. 모든 초점은 그 논리를 쓰는 데 있습니다.
이제 Go에서 함수를 생성하여 컨테이너 이미지로 빌드하고 로컬로 배치 및 실행하는 방법을 살펴보겠습니다. 그런 다음 이 함수를 OCI Functions 서비스로 가져와서 클라우드 쪽으로 실행하도록 하겠습니다.
기능을 개발하려면 프로젝트 Fn을 지원하는 환경이 필요합니다. Fn은 랩톱, 서버 또는 클라우드에서 실행할 수 있는 경량의 Docker 기반 서버리스 기능 플랫폼입니다. Fn Project Tutorials – Install Fn의 지침에 따라 Linux 또는 MacOS에 Fn을 쉽게 설치할 수 있습니다.
먼저 생성한 go-app-vm 컴퓨트 인스턴스에서 이 시리즈의 두번째 할부에 사용하도록 선택할 수 있습니다. 이 Oracle Linux 환경에는 Fn 설정이 제공되지 않지만 설치는 매우 간단합니다.
또는 OCI Cloud Shell에서 작업할 수 있습니다. 이 브라우저에 액세스할 수 있는 환경은 Fn으로 설정됩니다. OCI Cloud Shell에서 Fn으로 작업하는 방법은 OCI Documentation Functions: Get Started using Cloud Shell를 참조하십시오.
Fn CLI가 설치된 개발 환경에서 함수의 하위 디렉토리를 만들 디렉토리로 이동합니다. 명령줄에서 이 명령을 입력하고 실행합니다.
fn init --runtime go --trigger http greeter
greeter라는 하위 디렉토리가 생성됩니다. 탐색하여 내용을 확인합니다.
cd greeter ls -l
func.yaml 파일은 함수에 대한 메타 데이터를 포함하며, 빌드 시 Fn 프레임워크에서 해석되고, 나중에 함수를 실행할 때 해석됩니다. go.mod 파일은 함수가 fdk-go 패키지에 대해 갖는 종속성을 포함합니다. 실제 함수 자체는 func.go에 있습니다. 함수의 구조 및 Fn 런타임과의 상호 작용은 여기에서 볼 수 있습니다. function main은 함수 myHandler을 Fn 런타임에 등록하여 런타임이 수신된 모든 HTTP 요청에 대해 이 함수를 호출하도록 지시하고 사용으로 설정합니다. 함수는 io.Reader 매개변수에서 요청 본문을 수신합니다. 또한 응답 본문을 쓸 수 있는 io.Writer의 출력을 수신합니다. context.Context 매개변수 ctx에는 HTTP 헤더, 전체 URL, 요청 메소드 및 함수 자체(정의된 모든 구성 변수 포함)를 포함하여 원래 요청에 대한 메타 데이터가 포함됩니다.
현재 myHandler 함수는 name이라는 필드가 있는 JSON 페이로드를 포함할 것으로 예상하여 요청 본문을 디코딩합니다. 이름이 이 필드의 값으로 설정된 개인을 생성하거나, 없는 경우 기본적으로 World로 설정됩니다. 그런 다음 예상된 응답인 message라는 단일 필드를 가진 JSON 객체를 생성합니다. 여기에는 Hello로 구성된 문자열과 이름 값이 포함됩니다.
그것은 정말 멋진 아무것도하지 않지만, 기능은 건전하고 완전하고 우리는 로컬 배포하고 호출 할 수 있습니다. 이를 위해서는 로컬 컨텍스트가 필요하고 로컬 Fn 서버가 작동 및 실행 중이어야 합니다. 다음을 사용하여 컨텍스트를 확인합니다.
fn list contexts
하나 이상의 컨텍스트(하나 이상일 수 있음) 목록이 표시됩니다. 로컬 Fn 서버로 작업하려면 기본 컨텍스트가 활성 컨텍스트인지 확인합니다. 현재 컨텍스트를 기본값으로 설정하는 데 필요한 경우 다음을 사용합니다.
fn use context default
이제 응용 프로그램을 함수의 호스트로 생성합니다.
fn create app go-oci-app fn list apps
이러한 명령문 중 첫번째 명령문이 연결을 거부하여 실패하면 서버가 아직 실행되고 있지 않은 것입니다. 다음 명령을 사용하여 서버를 시작한 다음 응용 프로그램을 다시 만듭니다.
fn start
응용 프로그램이 성공적으로 생성되면 해당 응용 프로그램에 함수를 배치할 수 있습니다. 다음 명령은 이 배치를 처리합니다. 컨테이너 이미지 빌드 프로세스가 앞에 옵니다.
fn --verbose deploy --app go-oci-app --local
--local을 지정하면 로컬 서버에 배포되지만 함수 이미지를 Docker 레지스트리에 푸시하지 않습니다. 원격 Fn 서버에 배포하는 경우 필요합니다.
생성되는 로그 메시지의 인상적인 양을 해제하기 때문에 --verbose 플래그는 항상 사용할 플래그가 아닙니다. 그러나, 그것은 당신에게 무슨 일이 일어나고 있는지에 대한 꽤 좋은 통찰력을 제공합니다. 여러 컨테이너 이미지를 추출한 다음 2단계 컨테이너 빌드 프로세스가 실행되어 greeter 함수에 대한 컨테이너 이미지가 생성됩니다. 미리 정의된 Fn 프로젝트 이미지는 빌드 단계(쓰기 시 fnproject/go:1.15-dev) 및 런타임 이미지(fnproject/go:1.15)의 기초로 사용됩니다.
최종 출력은 다음과 같습니다.
Updating function greeter using image greeter:0.0.2... Successfully created function: greeter with greeter:0.0.2 Successfully created trigger: greeter Trigger Endpoint: http://localhost:8080/t/go-oci-app/greeter
함수 이미지를 greeter:0.0.2라고 합니다. 이 이미지는 로컬 컨테이너 레지스트리에서 다음과 함께 찾을 수 있습니다.
docker images | grep greeter
다음과 같이 이름 및 응용 프로그램을 사용하여 Fn CLI를 통해 함수를 호출할 수 있습니다.
fn invoke go-oci-app greeter
함수에는 이름 필드가 포함된 JSON 페이로드가 필요하므로 정확히 다음과 같이 제공하십시오.
echo -n '{"name":"Clark Kent"}' | fn invoke go-oci-app greeter --content-type application/json
함수 배치의 출력도 함수에 대한 트리거 끝점을 제공했습니다. HTTP 요청을 전송하여 함수를 트리거할 수 있는 HTTP 끝점입니다. 우리가 호출하는 엔드포인트가 실제로 Fn 서버 엔드포인트이지만 Fn과 (보이지 않는) 상호 작용은 없습니다. URL 경로는 Fn에게 응용 프로그램과 트리거할 특정 함수를 알려줍니다.
curl -X "POST" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse"}' http://localhost:8080/t/go-oci-app/greeter
이제 개발 환경이 아닌 OCI에서 이 함수를 생성해 보겠습니다. 단계는 로컬에서 함수를 생성하는 데 사용한 단계와 매우 유사합니다. 다른 컨텍스트만 사용해야 합니다. 로컬 컨텍스트가 아니라 OCI용 컨텍스트입니다.
애플리케이션 생성
먼저 OCI 콘솔을 통해 애플리케이션을 생성해 보겠습니다. 검색 상자에 app을 입력하고 서비스 영역에서 Applications Functions를 누릅니다.
애플리케이션 생성 버튼을 클릭합니다. 애플리케이션의 이름(go-on-oci-app)을 입력합니다. 문서 시리즈 중 일부와 하나의 퍼블릭 서브넷에서 생성된 VCN을 선택합니다. 그런 다음 Create를 눌러 응용 프로그램을 생성합니다.
OCI 상호 작용 및 기능 이미지 푸시를 위한 로컬 환경 준비
응용 프로그램이 생성되면 응용 프로그램에 대한 일반 정보가 표시됩니다. 이 페이지에는 OCI Cloud Shell 또는 로컬 설정(물론 go-app-vm 컴퓨트 인스턴스일 수 있음)에서 첫번째 함수를 생성하기 위한 지침도 포함되어 있습니다.
OCI Cloud Shell을 사용하는 경우 이 컨텍스트를 생성하는 단계는 일반 개발 환경에서 작업할 때와 약간 다르고 간단합니다. OCI Shell 설정을 따르십시오. 이 기사에서는 모든 지역 개발 환경에 사용되는 다른 경로를 취할 것입니다.
Fn CLI가 이전에 설치된 로컬 환경에서 수행할 단계는 다음과 같습니다.
다음 단계 이후 이 명령을 사용하여 1, 2, 4단계의 성공을 시도할 수 있습니다. 그러면 테넌시의 구획 목록이 반환됩니다.
oci iam compartment list
선택사항: 컨테이너 이미지 레지스트리 저장소 생성
함수 배치에 사용된 사용자 계정에 필요한 IAM 권한이 있는 경우 배치는 컨테이너 이미지 레지스트리의 함수 이미지에 대한 저장소를 생성합니다. 이러한 권한을 사용할 수 없거나 저장소를 준비하려는 경우 다음과 같이 준비할 수 있습니다.
Fn CLI에서 OCI에 대한 컨텍스트 생성
로컬 환경의 명령행으로 돌아가서 OCI의 현재 컴파트먼트에 대한 Fn 컨텍스트를 생성한 다음 Fn 작업에 사용하도록 선택해야 합니다. go-on-oci-app 페이지의 Getting Started 탭에서 복사할 수 있는 다음 명령을 실행합니다.
fn create context go-on-oci --provider oracle fn use context go-on-oci
4단계의 명령을 복사하여 컴파트먼트 OCID 및 Oracle Functions API URL로 컨텍스트를 업데이트합니다. 내 경우:
fn update context oracle.compartment-id ocid1.compartment.oc1..aaaaaaaaqb4vxvxuho5h7eewd3fl6dmlh4xg5qaqmtlcmzjtpxszfc7nzbyq fn update context api-url https://functions.us-ashburn-1.oraclecloud.com
명령은 유사하지만 서로 다릅니다.
고유한 저장소 이름 접두어를 제공하십시오. go-on-oci를 사용하여 함수 이미지를 게시해야 하는 이미지 레지스트리 저장소를 포함하는 컴파트먼트를 지정합니다.
fn update context registry iad.ocir.io/idtwlqf2hanz/go-on-oci fn update context oracle.image-compartment-id
인증 토큰을 비밀번호로 사용하여 레지스트리에 로그인합니다.
docker login iad.ocir.io
내 경우 내가 근무하는 지역은 애슈번이며 지역 키 iad.ocir.io로 식별됩니다. 사용자 이름을 입력하라는 메시지가 표시됩니다. 컨테이너 이미지 레지스트리 이름과 각 저장소에 포함된 네임스페이스 접두어를 포함하는 문자열입니다. 그런 다음 암호를 요청합니다. 여기서는 코드 저장소에서 로그인을 수행할 때 이전 문서에서 사용한 사용자에 대한 인증 토큰 설정을 제공합니다.
다음 명령은 현재 Fn 컨텍스트의 응용 프로그램 목록을 보여줍니다.
fn list apps
목록에는 go-on-oci-app이라는 하나의 애플리케이션이 포함되어 있습니다.
이전에 생성, 로컬 배포 및 호출된 greeter 함수를 이제 OCI 애플리케이션에 배포하여 클라우드 네이티브 서버리스 함수가 될 수도 있습니다. 배포에 사용하는 명령은 이전에 사용한 명령과 동일합니다. 그 효과는 변화된 상황으로 인해 극적으로 다릅니다. 로컬 컨텍스트 대신 이제 OCI 제공자를 기반으로 하고 OCI 테넌시 및 컴파트먼트에 링크된 컨텍스트가 있습니다. 컨테이너 이미지가 OCI Container Image Registry로 푸시되고 함수가 OCI Function 서비스에서 생성됩니다.
fn -v deploy --app go-on-oci-app
출력은 이전에 생성된 출력과 유사하지만 빌드 프로세스는 정확하게 동일합니다. 함수 컨테이너 이미지가 준비되면 상황이 편차되기 시작합니다. 이미지는 OCI 컨테이너 이미지 레지스트리에 푸시되고 함수는 클라우드에 배치됩니다. 출력의 관련 행:
=> exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:008dc3b990f1e69d67a7dd8649fbd63649d72f0bf1a161b2c2e073064f16c918 0.0s => => naming to iad.ocir.io/idtwlqf2hanz/go-on-oci/greeter:0.0.3 0.0s Parts: [iad.ocir.io idtwlqf2hanz go-on-oci greeter:0.0.3] Using Container engine docker to push Pushing iad.ocir.io/idtwlqf2hanz/go-on-oci/greeter:0.0.3 to docker registry...The push refers to repository [iad.ocir.io/idtwlqf2hanz/go-on-oci/greeter] ... e57f007acf74: Pushed 0.0.3: digest: sha256:bb4f2abde44d97517520571a21c407e349ddfc6572583a8ba53717436fd0b7f5 size: 1155 Updating function greeter using image iad.ocir.io/idtwlqf2hanz/go-on-oci/greeter:0.0.3... Successfully created function: greeter with iad.ocir.io/idtwlqf2hanz/go-on-oci/greeter:0.0.3 Fn: HTTP Triggers are not supported on Oracle Functions
이때 함수는 클라우드에 있으며 Fn CLI를 사용하여 호출할 수 있습니다.
fn invoke go-on-oci-app greeter
함수가 차갑게 시작되고 기본 컨테이너 이미지를 실행 중인 컨테이너로 인스턴스화해야 하므로 첫번째 호출은 상당히 시간이 걸립니다. 함수의 모든 후속 호출이 훨씬 빨라집니다. 10분 동안 기다린 후 함수가 콜링되면 컨테이너가 정지됩니다.
이 이미지는 우리가 도착한 상황을 설명합니다 :
OCI 콘솔에서 방금 발생한 증거를 확인할 수 있습니다. 콘솔의 검색 상자에 greeter를 입력합니다. Resources 아래에 >greeter > Functions> 항목이 있습니다. 링크를 눌러 함수에 대한 세부정보를 보여주는 페이지로 이동합니다. 함수 호출을 위한 함수 이미지, 메모리 설정 및 끝점에 대한 참조를 찾을 수 있습니다. 측정 단위에서 Fn CLI를 사용하여 수행된 함수 호출에 대한 증거를 찾아야 합니다.
greeter에 대한 검색 결과에서 Container Repository go-on-oci/greeter도 찾을 수 있습니다. 저장소로 이동하면 해당 저장소에 게시된 이미지에 대한 세부정보를 찾을 수 있습니다.
OCI 함수만 호출할 수는 없습니다. 그들은 단지 당신의 브라우저 또는 명령줄에 컬에서 그들을 호출 할 수 있다고 제안하는 HTTP 엔드포인트를 가지고 있지만, 실제로는 그렇게 간단하지 않습니다. 함수에 대한 HTTP 호출에 서명해야 하며 이 서명 프로세스는 간단하고 간단하지 않습니다.
소비자가 함수를 호출할 수 있도록 하는 더 좋은 방법은 API 게이트웨이를 사용하는 것입니다. 이전 기사에서는 API 게이트웨이를 사용하여 (잠재적으로) 전용 컴퓨팅 인스턴스에서 실행되는 myserver 애플리케이션에 대한 공용 경로를 열었습니다. 이제 API Gateway the-API-gateway의 추가 경로와 이전 기사에서 만든 배포 myserver-API를 사용하여 greeter 함수에 대해서도 동일한 작업을 수행합니다.
API 게이트웨이에 대한 IAM 액세스 설정
API 게이트웨이가 함수를 호출할 수 있도록 API 게이트웨이에 대한 권한을 제공하는 정책을 사용하여 API 게이트웨이가 함수를 호출하도록 허용되어야 합니다.
함수를 호출할 API Gateway에 대한 정책을 생성합니다. 콘솔에서 정책을 생성하려면 검색 도구 모음에 poli를 입력하고 검색 결과 팝업의 서비스 영역에서 >정책 > ID>를 누릅니다. 현재 컴파트먼트의 [정책 개요] 페이지로 이동합니다.
정책은 API 게이트웨이가 컴파트먼트의 리소스에 액세스할 수 있는 권한을 정의합니다. 새 정책을 생성하고 이름(invoke-function-for-api-gateway), 설명 및 다음 명령문을 입력합니다.
ALLOW any-user to use functions-family in compartment where ALL {request.principal.type= 'ApiGateway', request.resource.compartment.id = ' '}
API 게이트웨이의 배치에서 함수에 대한 경로 정의
처리된 권한으로 이제 API 게이트웨이에서 경로를 정의할 수 있습니다. 콘솔의 검색 표시줄에 gat를 입력합니다. Gateway > API Management를 누릅니다. *the-api-gateway에 대한 링크를 클릭하십시오. Deployments를 누릅니다. 배포 목록(단일 배포 포함)에서 myserver-api 링크를 누릅니다.
Edit 버튼을 눌러 배치 사양을 엽니다. 두번째 단계인 Routes에 대한 링크를 누릅니다. 아래로 스크롤하여 + Another Route 버튼을 누릅니다.
이 새 경로의 경로로 /greeting을 입력합니다. 메소드로 GET을 선택하고 백엔드의 유형으로 Oracle Functions를 선택합니다. application go-on-oci-app을 선택한 다음 Function Name을 greeter로 설정합니다.
Next를 누릅니다. 그런 다음 변경사항 저장을 눌러 변경사항을 적용하고 새 경로를 실제 경로로 설정합니다.
API 게이트웨이를 통해 함수 호출
새 경로가 설정되고 API 게이트웨이에서 배포가 새로 고쳐지면 이제 API 게이트웨이의 공용 엔드포인트로 간단하고 간단한 HTTP 요청을 생성하여 간접적으로 함수 greeter를 트리거하고 응답을 수신할 수 있습니다.
모든 브라우저에서 이 URL을 사용하면 함수의 응답을 얻을 수 있습니다.
https:///my-api/greeting
응답은 조금 압도적이지만, 그런 단순한 기능으로 예상된다.
curl을 사용하면 함수에 JSON 페이로드를 보내고 약간 더 흥미로운 응답을 받을 수 있습니다.
curl -X "GET" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse"}' https:///my-api/greeting
응답은 {"message":"Hello Mickey Mouse"}입니다.
이제 API 게이트웨이에서 서버리스 함수로의 엔드투엔드 플로우를 설정했습니다. 또한 로컬 개발 환경의 소스를 기반으로 기능을 수동으로 배포할 수 있습니다. 작업을 활용하기 위해 func.go에서 소스 코드를 몇 가지 변경한 다음 Fn CLI를 사용하는 단일 명령인 함수를 한 번 더 배치하고 API 게이트웨이에서 인사말 경로를 호출하여 변경 사항이 적용 중인지 확인할 수 있습니다.
예를 들어, Msg 값을 다음과 같이 설정하는 행을 변경합니다.
Msg: fmt.Sprintf("Warmest greetings from your function dear %s", p.Name)
업데이트된 func.go 소스를 저장합니다. 그런 다음 이러한 명령을 실행하여 갱신된 함수를 배치한 다음 호출합니다.
fn -v deploy --app go-on-oci-app
curl -X "GET" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse"}' https:///my-api/greeting
그러면 응답이 향상됩니다. 빌드 및 배포 프로세스는 준비된 환경에서 단일 수동 명령으로 압축됩니다. 다음으로는 OCI DevOps를 사용하는 함수에 대한 자동화된 배포 프로세스와 코드 저장소의 소스를 기반으로 한 이전의 자동화된 빌드 프로세스를 살펴봅니다. 그런 다음 간단한 인사말을 반환하는 것보다 조금 더 많은 기능을 수행 할 것입니다.
이 시리즈의 이전 버전에서는 OCI DevOps Deployment Pipelines을 사용하여 애플리케이션을 컴퓨트 인스턴스에 배포했습니다. 이제 함수의 자동 배포에 파이프라인을 사용합니다. 전체적인 접근과 성분은 비슷합니다. 아티팩트를 읽고 함수를 배치하려면 파이프라인에 대한 IAM 권한뿐만 아니라 함수 배치 단계가 있는 아티팩트, (대상) 환경 및 배치 파이프라인이 필요합니다.
이 성분은 더 상세하게:
OCI 콘솔에서 DevOps Project go-on-OCI의 홈 페이지로 이동합니다. 아티팩트 탭을 엽니다. 단추 아티팩트 추가를 누릅니다. 여기서 정의한 내용은 DevOps 프로젝트에서 실제 아티팩트로의 링크 또는 프록시이며 아티팩트 자체는 아닙니다.
DevOps 아티팩트의 이름으로 greeter-function을 입력합니다. 유형을 컨테이너 이미지 저장소로 설정해야 합니다. 이미지의 전체 경로는 영역 키, 저장소 네임스페이스 및 접두어, 함수 이름 및 함수 버전 태그로 구성됩니다. 이 경우 버전 태그에 대해 위치 표시자를 사용합니다. 이제 경로가 다음과 같이 정의됩니다.
///greeter:${imageVersion}
드롭다운 필드를 설정합니다. 이 아티팩트에 사용된 매개변수를 예로 바꾸고 위치 표시자를 대체합니다.
추가 단추를 눌러 아티팩트의 정의를 완료하고 저장합니다.
DevOps 프로젝트에서 Environments 탭을 엽니다. 이전 기사에서 myserver를 컴퓨트 인스턴스에 배치하기 위해 생성된 go-on-oci-vm 환경이 포함되어 있습니다. 환경 생성 버튼을 클릭하십시오.
첫 번째 단계인 기본 정보에서 타일 함수 - 함수에 대한 환경 생성을 클릭합니다. 환경 이름으로 greeter-function-in-app-go-on-oci-app을 입력합니다. [다음]을 눌러 환경 세부정보와 함께 두번째 단계로 이동합니다. Region, Compartment, Application 및 Function을 확인합니다. 이러한 설정을 변경할 필요가 없을 것입니다. 이렇게 하면 응용 프로그램 go-on-oci-app의 greeter 함수가 선택되었는지 확인합니다.
환경 생성을 눌러 정의를 저장합니다.
DevOps 프로젝트의 개요 페이지에서 [파이프라인 생성]을 누릅니다. Create pipeline form이 표시됩니다. 이름(deploy-greeter-function-to-go-on-oci-app) 및 선택적으로 설명을 입력합니다. 그런 다음 Create pipeline을 누릅니다. 배치 파이프라인이 상당히 비어 있지만, 배치할 환경이 아니고, 배치할 아티팩트가 없으며, 실행할 단계를 정의할 구성 파일이 없습니다.
표시되는 파이프라인 편집기에서 [단계 추가] 타일(또는 더하기 아이콘)을 클릭합니다. 다음 페이지에는 스테이지 유형 목록이 표시됩니다. Usees the built-in Functions update strategy(기본 제공 함수 업데이트 전략 사용)로 표시된 타일을 누릅니다.
다음을 누르십시오.
단계 이름(예: update-function-greeter)을 입력합니다. 이전에 함수에 대해 정의된 환경(greeter-function-in-app-go-on-oci-app)을 선택합니다.
[아티팩트] 머리글 아래에서 [아티팩트 선택]을 누릅니다. Docker 이미지 유형의 DevOps 프로젝트에 있는 모든 아티팩트 목록이 표시됩니다. 함수 컨테이너 이미지에 대해 이전에 생성된 항목만 선택합니다.
아티팩트 선택 단추가 더 이상 사용으로 설정되지 않습니다. 단일 컨테이너 이미지만 이 단계와 연관될 수 있습니다.
추가를 클릭합니다. 파이프라인 단계가 파이프라인에 생성됩니다. 이제 파이프라인을 실행할 준비가 되었습니다. 정의가 완료되었습니다. 또는 그렇습니까? 이 파이프라인이 사용하는 아티팩트가 불균등하게 정의되지 않았습니다. 컨테이너 이미지 경로의 버전 레이블에 위치 표시자 ${imageVersion}이(가) 포함되어 있습니다. 적절한 버전이 배치에 사용되도록 하려면 이 위치 표시자를 올바른 값으로 바꿔야 합니다. imageVersion이라는 매개변수를 파이프라인에 정의하고 기존 버전 레이블로 설정하여 정렬합니다.
파이프라인에 대한 매개변수 탭을 누릅니다. imageVersion이라는 새 매개변수를 정의합니다. 기본값은 무엇이든 될 수 있지만 greeter 함수 컨테이너 이미지의 기존 버전 레이블과 일치할 수도 있습니다. 매개변수 정의를 저장합니다.
파이프라인을 실행할 준비가 된 것 같지만 작업을 수행할 수 있는지 확인해야 합니다. 어떤 것을 시도하기 전에, 다음 섹션을 읽으십시오.
이전 문서에서는 컴파트먼트의 모든 배치 파이프라인에 대해 동적 그룹이 정의되었습니다. 새 파이프라인은 자동으로 해당 그룹의 멤버입니다. 또한 컴파트먼트의 컨테이너 이미지 레지스트리 저장소에 (함수) 컨테이너 이미지를 포함하는 모든 아티팩트를 읽기 위해 동적 그룹에 권한을 부여하는 정책을 정의했습니다. 또한 이미 생성된 다른 정책은 컴파트먼트의 모든 리소스를 관리할 수 있는 매우 광범위한 권한을 동적 그룹에 부여합니다. 우리는 또한 기능의 창조 그리고 갱신을 다루기 때문에 그 정책의 넓은 범위의 이익을 얻을 수 있다.
Run pipeline을 눌러 Deployment Pipeline을 실행합니다.
배포가 완료되면 성공을 선언하는 녹색 표시자가 표시됩니다. 그러나 최종 결과는 Fn CLI 명령줄에서 함수를 수동으로 배치하여 얻은 상황이므로 이 성공에 대한 다른 명백한 표시는 없습니다.
조금 더 흥미로운 것을 만들기 위해, 우리는 함수의 코드를 변경할 것입니다. 그런 다음 함수에 대한 컨테이너 이미지를 로컬로 작성하고 새 함수 이미지를 컨테이너 이미지 레지스트리에 푸시합니다. 그런 다음 배포 파이프라인을 다시 시작합니다. 이번에는 성공하면 API 게이트웨이에서 my-API/인사말 경로를 호출하여 경험할 수 있는 새로운 상황이 렌더링됩니다.
변경 기능 구현
로컬 환경에서 작지만 보이는 대로 func.go를 변경합니다. 새 버전의 함수의 응답이 현재 버전과 현저하게 다르게 나타나는지 확인합니다. 변경 사항을 저장합니다.
다음 섹션에서는 변경된 소스에서 함수 컨테이너 이미지의 새 버전을 빌드하고 결국 OCI Functions에서 실행됩니다.
새 함수 컨테이너 이미지 작성(로컬)
다음 명령은 먼저 세번째 자릿수가 증가하도록 함수에 태그를 지정하는 데 사용되는 버전 레이블을 수정합니다(bm은 범프의 경우 짧음). 다음으로, 함수 컨테이너 이미지는 변경된 소스를 사용하여 작성됩니다. 세번째 명령은 로컬 컨테이너 이미지를 나열하고 이름에 greeter가 있는 이미지를 필터링합니다. 이제 명령을 실행하십시오.
fn bm
fn build
docker images | grep greeter
OCI 리전 키, 네임스페이스, 저장소 접두어 및 버전 레이블이 추가된 함수 이름 greeter를 포함하여 완전히 정규화된 이름으로 새로 빌드된 이미지를 찾을 수 있어야 합니다.
컨테이너 이미지에 새 버전 레이블 태그 지정 및 레지스트리로 푸시
버전 레이블을 0.1.0으로 설정하는 이 명령을 사용하여 이미지에 대한 새 식별자를 정의해 보겠습니다.
docker tag : :0.1.0
그런 다음 다음을 사용하여 새 함수 컨테이너 이미지를 OCI 컨테이너 이미지 레지스트리 저장소로 푸시합니다.
docker push :0.1.0
이 시점에서 이 새 버전의 컨테이너 이미지를 기반으로 함수를 재배치하지 않았습니다. 이미지를 구축하고 OCI의 레지스트리에 푸시하기만 하면 됩니다. OCI 함수를 호출해도 차이가 표시되지 않습니다.
새 함수 이미지에 대해 배치 파이프라인 실행
배치 파이프라인을 한 번 더 실행합니다. 매개변수 imageVersion의 값을 0.1.0으로 설정합니다.
파이프라인이 성공적으로 완료되면 적용한 모든 흥미로운 변경 사항과 함께 새 버전의 함수가 활성화됩니다.
새로 배치된 함수 호출
Fn CLI를 사용하여 명령줄에서 호출하면 새 함수 버전이 실제로 작동하는지 확인할 수 있습니다.
fn invoke go-on-oci-app greeter
(Fn CLI의 컨텍스트는 여전히 Oracle 제공자와의 go-on-OCI이고 greeter 함수가 포함된 go-on-OCI 컴파트먼트에 대해 구성되었으므로 이 호출은 OCI 함수로 전달됩니다. 이때 OCI 함수는 새 버전의 컨테이너 이미지를 기반으로 합니다.)
또는 함수를 호출하는 API 게이트웨이의 경로로 컬할 수 있습니다.
curl -X "GET" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse"}' https:///my-api/greeting
지금까지 Fn CLI를 사용하여 로컬 개발 환경에서 기능 컨테이너 이미지를 직접 구축했습니다. 그러나 Build Pipeline에서 실행 가능으로 제작한 Go 응용 프로그램의 이전 기사에서와 마찬가지로 이제 기능 구축을 자동화된 프로세스로 전환할 것입니다. OCI DevOps 빌드 파이프라인이 생성되어 코드 저장소에서 소스를 가져오고, 로컬 컨테이너 이미지를 생성하는 관리형 빌드 단계를 실행하고, 이 이미지를 컨테이너 이미지 레지스트리 저장소에 아티팩트로 게시합니다. 마지막으로 Build Pipeline은 Deployment Pipeline을 트리거하여 함수의 최신 정의를 런타임 OCI Functions 환경에 게시합니다.
모든 요소가 배치되면 상호 연결된 총 OCI 구성요소 집합이 다음 그림에서 시각화된 것처럼 보입니다.
이 그림에 표시된 아티팩트 및 배치 파이프라인은 함수 이미지에 대한 애플리케이션, 함수 및 컨테이너 이미지 레지스트리 저장소와 같이 이미 DevOps 프로젝트에 정의되어 있습니다. 이전 문서에서 설정된 코드 저장소를 사용합니다. 세 단계로 구성된 Build Pipeline 빌드-더 큰 기능만 생성하면 됩니다.
빌드 파이프라인 생성
DevOps Project go-on-oci에 대한 개요 페이지에서 빌드 파이프라인 생성 단추를 누릅니다. 이름을 지정하는 페이지(예: build-greeter-function)와 설명을 제공합니다. [생성]을 눌러 빌드 파이프라인을 DevOps 프로젝트에 추가합니다.
목록에서 링크 build-greeter-function을 눌러 세부정보 페이지로 이동합니다.
첫번째 단계 – 관리형 빌드
빌드 파이프라인의 첫번째 단계는 관리형 빌드 단계입니다. 이 단계에서는 파이프라인이 빌드 서버를 보류하고, 지정된 소스를 코드 저장소에서 서버로 복사하고, 해당 서버에서 여러 작업을 통해 실행하도록 하는 지침을 제공합니다. 이 글을 쓸 때 빌드 서버에 단일 이미지를 사용할 수 있습니다. Oracle Linux 이미지(8GB 메모리, OCPU 1개)로, 사전 설치된 툴과 언어 런타임이 많습니다. 함수 컨테이너 이미지를 빌드할 때는 빌드 서버에 Docker 및 Fn CLI가 모두 장착되어 있어야 합니다.
더하기 아이콘 또는 스테이지 추가 카드를 누릅니다. 단계 추가 마법사가 나타납니다. 마법사의 1단계에서 스테이지 유형에 대해 관리형 빌드 카드가 선택되어 있는지 확인합니다. Next를 누릅니다.
두번째 페이지가 표시됩니다. 빌드 단계에 대한 이름(build-go-source-to-function-container-image)을 정의합니다. 선택적으로 설명을 추가합니다.
현재 다른 빌드 이미지를 선택할 수 없으므로 사용 가능한 이미지를 선택할 수 있으며 이는 목적상 괜찮습니다.
Build spec file path를 /functions/greeter/go-function-build-spec.yaml로 설정합니다. 이 파일에는 greeter 함수(또는 다른 Go 함수)에서 Go 소스를 빌드하고 마지막으로 함수 컨테이너 이미지를 빌드하는 지침이 포함되어 있습니다.
Primary code repository 아래의 Select 버튼을 누릅니다. 이제 빌드의 소스를 가져올 코드 저장소를 지정할 수 있습니다. Source Connection Type으로 OCI Code Repository를 선택합니다. 그런 다음 go-on-oci-repo 저장소를 선택합니다. 기본 분기에서 소스로 작업하므로 해당 기본값을 변경하지 마십시오. 빌드 소스 이름에 대한 값으로 go-on-oci-sources를 입력합니다. 관리형 빌드 단계에서는 여러 저장소의 소스를 사용할 수 있습니다. 빌드 사양에서는 빌드 소스 이름으로 정의된 레이블을 사용하여 이러한 각 소스의 루트 위치를 참조할 수 있습니다. [저장]을 클릭합니다.
추가 단추를 누릅니다. 관리형 빌드 단계의 정의를 완료합니다. 소스를 가져와 아티팩트로 처리하는 데 필요한 모든 것입니다. 이 관리형 빌드 단계 및 빌드 서버에서 실행되는 자세한 지침은 go-function-build-spec.yaml 파일에 정의되어 있습니다. 이 파일에는 빌드 서버에서 실행된 실제 세부 단계에 대한 지침이 포함되어 있습니다.
version: 0.1
component: build
timeoutInSeconds: 6000
runAs: root
shell: bash
env:
# these are local variables to the build config
variables:
SOURCE_DIRECTORY: "go-on-oci-sources/functions/greeter"
FUNCTION_NAME: "greeter"
# # the value of a vaultVariable is the secret-id (in OCI ID format) stored in the OCI Vault service
# you can then access the value of that secret in your build_spec.yaml commands
vaultVariables:
# exportedVariables are made available to use in sucessor stages in this Build Pipeline
# For this Build to run, the Build Pipeline needs to have a BUILDRUN_HASH parameter set
exportedVariables:
- BUILDRUN_HASH
steps:
- type: Command
name: "Export variables"
timeoutInSeconds: 40
command: |
export BUILDRUN_HASH=`echo ${OCI_BUILD_RUN_ID} | rev | cut -c 1-7`
echo "BUILDRUN_HASH: " $BUILDRUN_HASH
echo "fully qual sources" ${OCI_WORKSPACE_DIR}/${SOURCE_DIRECTORY}
echo "container image version from build pipeline parameter" ${imageVersion}
go version
- type: Command
timeoutInSeconds: 600
name: "Install golangci-lint"
command: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.37.1
- type: Command
timeoutInSeconds: 600
name: "Verify golangci-lint version"
command: |
/root/go/bin/golangci-lint version
- type: Command
timeoutInSeconds: 600
name: "Run go mod tidy for Go Application"
command: |
cd ${OCI_WORKSPACE_DIR}/${SOURCE_DIRECTORY}
go mod tidy
- type: Command
timeoutInSeconds: 600
name: "Run go vet for Go Application"
command: |
cd ${OCI_WORKSPACE_DIR}/${SOURCE_DIRECTORY}
go vet .
- type: Command
timeoutInSeconds: 600
name: "Run gofmt for Go Application"
command: |
gofmt -w ${OCI_WORKSPACE_DIR}/${SOURCE_DIRECTORY}
- type: Command
timeoutInSeconds: 600
name: "Run Lint for Go Application"
command: |
cd ${OCI_WORKSPACE_DIR}/${SOURCE_DIRECTORY}
/root/go/bin/golangci-lint run .
- type: Command
timeoutInSeconds: 600
name: "Run Unit Tests for Go Application (with verbose output)"
command: |
cd ${OCI_WORKSPACE_DIR}/${SOURCE_DIRECTORY}
go test -v
- type: Command
timeoutInSeconds: 600
name: "Build Go Function into Function Container Image"
command: |
cd ${OCI_WORKSPACE_DIR}/${SOURCE_DIRECTORY}
pwd
fn build --verbose
image=$(docker images | grep $FUNCTION_NAME | awk -F ' ' '{print $3}') ; docker tag $image go-function-container-image
outputArtifacts:
- name: go-function-container-image
type: DOCKER_IMAGE
# this location tag doesn't effect the tag used to deliver the container image
# to the Container Registry
location: go-function-container-image:latest
빌드 사양은 다음 세 부분으로 구성됩니다.
빌드 단계는 다음과 같이 요약할 수 있습니다.
이러한 단계는 최종적으로 VM에 배치된 이진 실행 파일로 변환된 Go 응용 프로그램에 대해 이전 문서에서 정의된 관리형 빌드와 거의 동일합니다. 9단계와 10단계는 다릅니다. 그러면 Go 응용 프로그램이 빌드의 최종 제품인 Function Container Image로 바뀝니다.
두 번째 단계 - 아티팩트 게시
빌드 파이프라인에 대한 개요 페이지에서 현재 관리되는 빌드 단계 아래쪽의 더하기 아이콘을 누릅니다. 팝업되는 컨텍스트 메뉴에서 Add stage를 누릅니다. 스테이지 마법사가 나타납니다.
아티팩트 전달을 누릅니다. 그런 다음 Next를 누릅니다.
이 단계의 이름(publish-greeter-function-container-image)을 입력합니다. 게시할 DevOps 프로젝트에서 아티팩트를 선택해야 합니다. 이 아티팩트는 컨테이너 이미지 go-on-oci/greeter:${imageVersion}입니다. 아티팩트 선택을 누르고 컨테이너 이미지를 선택합니다.
아티팩트와 빌드 결과 연관 영역에서 선택한 각 아티팩트에 대해 관리되는 빌드 단계의 결과가 아티팩트를 게시하기 위한 소스임을 나타내야 합니다. 빌드 사양은 go-function-container-image 레이블이 지정된 출력을 정의합니다. 이 출력은 함수 빌드 프로세스에 의해 빌드 서버에서 생성된 컨테이너 이미지를 나타냅니다. 빌드 구성/결과 아티팩트 이름 필드에 go-function-container-image 레이블을 입력합니다. [추가] 단추를 눌러 아티팩트 전달 단계를 생성합니다.
세번째 단계 – 배치 파이프라인 트리거
빌드 파이프라인에 대한 개요 페이지에서 아티팩트 전달 단계 아래쪽에 있는 더하기 아이콘을 누릅니다. 팝업되는 컨텍스트 메뉴에서 Add stage를 누릅니다. 스테이지 마법사가 나타납니다.
Trigger deployment를 누릅니다. 그런 다음 다음을 클릭합니다.
단계의 이름(trigger-deployment-of-greeter-function-to-go-on-oci-app)과 선택적으로 설명을 입력합니다. Select deployment pipeline 단추를 누릅니다. pipeline deploy-greeter-function-to-go-on-oci-app를 선택합니다. 매개변수(imageVersion) 및 배치에 사용된 아티팩트를 포함한 파이프라인 세부정보가 표시됩니다.
[추가]를 눌러 단계 정의를 완료하고 빌드 파이프라인에 추가합니다.
이렇게 해서 빌드 파이프라인이 완성되었습니다. 즉, 소스를 확보하고 배치 가능한 아티팩트로 처리하고, 아티팩트를 이미지 저장소에 게시하고, 배치 파이프라인을 트리거하여 여기서 가져옵니다.
Start manual run을 누릅니다. imageVersion 매개변수에 대한 값을 정의합니다(예: 0.2.0). 빌드 파이프라인을 실행하려면 단추를 누릅니다.
이제 빌드 파이프라인을 완료하고 새로 빌드된 함수 이미지의 후속 배치를 트리거하는 데 몇 분 정도 걸립니다.
모든 작업이 완료되고 성공이 보고되면 더 친숙한 함수로 이어지는 API 게이트웨이에서 경로를 호출하여 응답이 실제로 예상한 새 응답인지 확인할 수 있습니다.
curl -X "GET" -H "Content-Type: application/json" -d '{"name":"Mickey Mouse"}' https:///my-api/greeting
{"message":"Extremely hot greetings from your automatically built and deployed function dear Mickey Mouse"}
이것은 약간의 축하를위한 순간입니다. Code Repository에서 Go 애플리케이션 소스를 가져와 서버리스 OCI 함수의 새 버전을 실시간으로 실행한 후 제공하는 자동화된 엔드 투 엔드 프로세스를 달성했습니다. 함수에 대한 추가 업데이트를 생성하기 위해 변경사항을 커밋하고 빌드 파이프라인을 트리거하기만 하면 됩니다. 그리고 다음 단계에서는 코드 저장소에서 (특정) 커밋이 발생할 때 빌드 파이프라인을 자동으로 트리거할 수도 있습니다.
이 문서의 두 번째 부분에서는 일반적으로 Go 애플리케이션의 OCI 서비스 및 특히 Go 기능의 사용에 대해 논의합니다. OCI용 Go SDK가 도입되었으며 OCI Object Storage Service와의 상호 작용이 시연되었습니다.
Oracle Cloud Infrastructure는 Go에서 개발된 애플리케이션을 구축 및 실행할 수 있는 플랫폼입니다. 컴퓨팅 인스턴스 또는 서버리스 기능 중 하나이며 관리형 Kubernetes 클러스터에도 컨테이너화되어 있습니다(이 시리즈 중 5부에서는 설명하겠습니다). OCI가 런타임 플랫폼보다 Go 개발 팀에 훨씬 더 적합하다는 것을 깨닫는 것이 좋습니다. OCI는 애플리케이션에서 활용할 수 있는 다양한 서비스를 제공합니다. 메시지 게시 및 사용을 처리하기 위한 파일, 관계형 또는 "NoSQL" 데이터 저장 서비스입니다. 데이터 전송 및 분석을 위한 서비스입니다. 모니터링과 같은 애플리케이션에 대한 작업을 지원하는 서비스입니다.
OCI 서비스와의 상호 작용은 모든 서비스의 모든 측면에서 사용할 수 있는 REST API를 통해 수행할 수 있습니다. HTTP를 통한 JSON 페이로드로 REST 서비스를 호출하는 것은 Go 애플리케이션에서 충분히 쉽습니다. 이러한 API 호출에 서명해야 한다는 하나의 복잡한 요소가 있습니다. Oracle Cloud Infrastructure 서명은 "서명" 인증 체계(권한 부여 헤더 포함)를 사용하며 서명 프로세스가 정확하지 않습니다. 이 서명 프로세스에 대한 자세한 내용은 OCI 설명서 – OCI REST API 요청 서명을 참조하십시오.다행히 OCI 서비스를 호출하는 Go 애플리케이션을 개발하기 위해 Go SDK for OCI를 사용할 수 있습니다. 이 오픈 소스 개발 키트는 OCI API 요청 서명을 용이하게 합니다. SDK를 사용하면 OCI 서비스에 대한 호출은 JSON 요청 및 응답 본문을 처리하는 대신 강력하게 입력된 미리 정의된 구조를 사용하여 로컬 호출로 이루어집니다. OCI용 Go SDK는 이전에 Fn CLI 및 OCI CLI에 대해 사용한 것과 동일한 구성 파일을 사용합니다. 이 파일의 기본 위치는 $HOME/.oci입니다. 이 파일은 Go SDK를 사용자에 대해 설정된 쌍의 절반 개인 키를 사용하여 사용자 계정에 대한 특정 테넌시 및 지역으로 지정합니다. Go SDK for OCI를 사용하는 Go 애플리케이션은 세부 사항을 처리하지 않고도 이 구성을 기반으로 구축할 수 있습니다.
OCI용 Go SDK 설명서는 OCI Documentation – SDK for Go에서 확인할 수 있습니다.
이 섹션에서는 OCI Object Storage Service를 사용하여 파일을 생성하고 읽는 간단한 Go 애플리케이션을 개발합니다. 처음에는 OCI 구성 파일을 사용할 수 있는 한 모든 곳에서 컴파일하고 실행할 수 있는 독립형 애플리케이션입니다. 그런 다음 OCI 내에서 VM 또는 Function으로 Go 애플리케이션을 실행하는 방법에 대해 논의합니다. 이 특별한 초점은 Go SDK가 OCI 내에서 사용될 때 애플리케이션을 실행하는 구성요소의 ID 및 권한을 활용할 수 있다는 점입니다. 즉, OCI에서 실행되는 코드는 자체 OCI 구성 파일을 가져올 필요가 없으므로 더욱 간단합니다.
먼저 SDK를 통해 OCI에 연결할 수 있는 매우 간단한 Go 애플리케이션을 생성해 보겠습니다. 다음으로 이 토대를 사용하여 오브젝트 스토리지 서비스와 상호 작용을 추가합니다.
OCI의 Simplest Go 클라이언트
OCI용 Go SDK를 사용하여 OCI와 통신하는 가장 간단한 Go 애플리케이션은 다음과 같이 생성됩니다.
이 문서 앞부분에서 설명한 OCI 구성 파일은 기본 위치인 $HOME/.oci/config에 있다고 가정합니다. 파일이 다른 위치에 있는 경우 구성 파일의 사용자 정의 위치를 받아들이는 github.com/oracle/oci-go-sdk/v65/common 패키지의 ConfigurationProviderFromFile 함수를 사용할 수 있습니다.
go.mod 파일에는 다음 내용이 포함되어 있습니다.
module oci-client
go 1.16
require github.com/oracle/oci-go-sdk/v65 v65.2.0
github.com/oracle/oci-go-sdk/v65 비트는 Go SDK의 최신(쓰기 시) 버전을 참조합니다. 소스는 이 참조를 기반으로 다운로드됩니다. Go 애플리케이션에서는 SDK의 패키지를 활용하여 OCI 포트폴리오의 다양한 서비스에 액세스할 수 있습니다.
oci-client.go 파일은 공통 및 ID 패키지를 사용하는 다음 코드를 포함합니다.
package main
import (
"context"
"fmt"
"github.com/oracle/oci-go-sdk/v65/common"
"github.com/oracle/oci-go-sdk/v65/identity"
)
func main() {
c, _ := identity.NewIdentityClientWithConfigurationProvider(common.DefaultConfigProvider())
tenancyID, _ := common.DefaultConfigProvider().TenancyOCID()
request := identity.GetCompartmentRequest{
CompartmentId: &tenancyID,
}
response, _ := c.GetCompartment(context.Background(), request)
fmt.Printf("Name of Root Compartment: %v", *response.Compartment.Name)
}
함수의 첫번째 행은 루트 컴파트먼트에 대한 세부 정보를 반환하는 GetCompartment 호출과 같이 이후에 OCI와의 대부분의 상호 작용에 사용할 수 있는 클라이언트를 획득합니다.
응용 프로그램은 go run oci-client.go를 사용하여 실행할 수 있으며 매우 간단한 출력을 생성합니다.
Name of Root Compartment:
결과가 특히 주목할 만한 것은 아니지만, 출력이 있다는 사실은 OCI용 Go SDK가 작동 중이며 더 많은 로프트 활동을 위해 활용할 준비가 되었다는 증거입니다.
코드는 발생할 수 있는 오류를 완전히 무시합니다. 오류가 발생하면 밑줄을 해당 오류를 캡처하고 처리하기 위한 변수로 바꿉니다.
OCI 오브젝트 스토리지 서비스에서 객체 생성 및 검색 애플리케이션으로 이동
OCI Object Storage Service는 다양한 유형의 데이터에 대해 저렴하고 영구적인 스토리지를 제공합니다. 크고 작은 객체는 이 서비스에 프로그래밍 방식으로 저장되어 단기 또는 장기간 보관할 수 있으며 프로그래밍 방식으로 또는 직접 URL을 통해 액세스할 수 있습니다. Object Storage는 버전 지정, 다양한 보존 규칙, 저장된 데이터의 암호화, 객체 수명 주기 관리, 자동화된 시간 기반 제거 및 다양한 스토리지 계층을 제공합니다.
오브젝트 스토리지 서비스의 오브젝트는 버킷으로 구성됩니다. 버킷은 특정 구획에 있는 객체의 논리적 컨테이너입니다. 일부 작업은 버킷의 모든 객체에 대해 수행할 수 있습니다.
OCI용 Go SDK는 Go 애플리케이션에서 Object Storage Service를 쉽고 간단하게 사용할 수 있는 기능과 유형을 제공합니다. 버킷을 조작하고 객체를 생성, 삭제 및 검색하는 작업을 쉽게 수행할 수 있습니다.
OCI용 Go SDK의 Object Storage 패키지에 대한 자세한 내용은 OCI용 Go SDK의 Object Storage Package 설명서를 참조하십시오.
이 문서의 소스 저장소에는 폴더 애플리케이션/store-n-retrieve가 포함되어 있습니다. 이 애플리케이션에는 OCI 테넌시에 접속하여 버킷을 생성한 후 객체를 생성하고 동일한 객체를 검색하는 간단한 Go 애플리케이션이 있습니다. 애플리케이션은 이전 섹션에서 사용한 것과 동일한 DefaultConfigProvider를 사용하여 $HOME/.oci/config 파일을 사용하여 OCI API에 요청을 서명합니다.
OCI용 Go SDK에서 이 애플리케이션의 종속성은 go.mod에 정의되어 있습니다.
코드의 첫번째 부분은 ObjectStorageClient 인스턴스를 생성합니다. 기본 인터페이스에는 여러 기능이 정의되어 있으며 이 모든 기능이 오브젝트 스토리지 서비스와의 상호 작용을 지원합니다. ObjectStorageClient는 프라이빗 키가 포함된 파일에 대한 참조와 함께 기본 OCI 구성 파일을 사용하여 common.DefaultConfigProvider()을 사용하여 생성됩니다.
현재 테넌시에 대한 네임스페이스를 가져오기 위해 getNamespace 함수가 호출됩니다. 그런 다음 버킷이 존재하지 않을 경우 버킷 이름을 사용하여 ensureBucketExists가 호출됩니다.
package main
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"github.com/oracle/oci-go-sdk/v65/common"
"github.com/oracle/oci-go-sdk/v65/objectstorage"
)
const (
bucketName = "go-bucket" // feel free to use a different name for the bucket
compartmentOCID = " " // replace with the OCID of the go-on-oci compartment in your tenancy
objectName = "welcome.txt" // feel free to use a different name for the object
)
func main() {
objectStorageClient, cerr := objectstorage.NewObjectStorageClientWithConfigurationProvider(common.DefaultConfigProvider())
if cerr != nil {
fmt.Printf("failed to create ObjectStorageClient : %s", cerr)
}
ctx := context.Background()
namespace, cerr := getNamespace(ctx, objectStorageClient)
if cerr != nil {
fmt.Printf("failed to get namespace : %s", cerr)
} else {
fmt.Printf("Namespace : %s", namespace)
}
err := ensureBucketExists(ctx, objectStorageClient, namespace, bucketName, compartmentOCID)
if err != nil {
fmt.Printf("failed to read or create bucket : %s", err)
}
.........................
네임스페이스를 검색하고 버킷이 존재하는지 확인하기 위해 이 코드 조각에서 호출된 함수(없는 경우 생성)는 매우 간단합니다. 다음과 같이 정의됩니다.
func getNamespace(ctx context.Context, client objectstorage.ObjectStorageClient) (string, error) {
request := objectstorage.GetNamespaceRequest{}
response, err := client.GetNamespace(ctx, request)
if err != nil {
return *response.Value, fmt.Errorf("failed to retrieve tenancy namespace : %w", err)
}
return *response.Value, nil
}
func ensureBucketExists(ctx context.Context, client objectstorage.ObjectStorageClient, namespace string, name string, compartmentOCID string) error {
req := objectstorage.GetBucketRequest{
NamespaceName: &namespace,
BucketName: &name,
}
// verify if bucket exists.
response, err := client.GetBucket(ctx, req)
if err != nil {
if response.RawResponse.StatusCode == 404 {
err = createBucket(ctx, client, namespace, name, compartmentOCID)
return err
}
return err
}
fmt.Printf("bucket %s already exists", bucketName)
return nil
}
// bucketname needs to be unique within compartment. there is no concept of "child" buckets. using "/" separator characters in the name, the suggestion of nested bucket can be created
func createBucket(ctx context.Context, client objectstorage.ObjectStorageClient, namespace string, name string, compartmentOCID string) error {
request := objectstorage.CreateBucketRequest{
NamespaceName: &namespace,
}
request.CompartmentId = &compartmentOCID
request.Name = &name
request.Metadata = make(map[string]string)
request.PublicAccessType = objectstorage.CreateBucketDetailsPublicAccessTypeNopublicaccess
_, err := client.CreateBucket(ctx, request)
if err != nil {
return fmt.Errorf("failed to create bucket on OCI : %w", err)
} else {
fmt.Printf("created bucket : %s", bucketName)
}
return nil
}
이 응용 프로그램의 두번째 부분은 버킷에 객체를 생성한 다음 해당 객체를 검색합니다. 응용 프로그램 실행이 완료되면 버킷이 생성되고(없는 경우) 객체가 생성 또는 갱신되었으며(이전에 응용 프로그램을 실행한 경우) 객체가 지속적으로 영향을 받습니다. OCI 콘솔에서 버킷 이동 버킷에 대한 세부정보 페이지를 체크인하여 생성된 버킷과 객체를 모두 확인할 수 있습니다.
..................
contentToWrite := []byte("We would like to welcome you in our humble dwellings. /n We consider it a great honor. Bla, bla.")
objectLength := int64(len(contentToWrite))
err = putObject(ctx, objectStorageClient, namespace, bucketName, objectName, objectLength, ioutil.NopCloser(bytes.NewReader(contentToWrite)))
if err != nil {
fmt.Printf("failed to write object to OCI Object storage : %s", err)
}
var contentRead []byte
contentRead, err = getObject(ctx, objectStorageClient, namespace, bucketName, objectName)
if err != nil {
fmt.Printf("failed to get object %s from OCI Object storage : %s", objectName, err)
}
fmt.Printf("Object read from OCI Object Storage contains this content: %s", contentRead)
}
func putObject(ctx context.Context, client objectstorage.ObjectStorageClient, namespace string, bucketName string, objectname string, contentLen int64, content io.ReadCloser) error {
request := objectstorage.PutObjectRequest{
NamespaceName: &namespace,
BucketName: &bucketName,
ObjectName: &objectname,
ContentLength: &contentLen,
PutObjectBody: content,
}
_, err := client.PutObject(ctx, request)
fmt.Printf("Put object %s in bucket %s", objectname, bucketName)
if err != nil {
return fmt.Errorf("failed to put object on OCI : %w", err)
}
return nil
}
func getObject(ctx context.Context, client objectstorage.ObjectStorageClient, namespace string, bucketName string, objectname string) (content []byte, err error) {
request := objectstorage.GetObjectRequest{
NamespaceName: &namespace,
BucketName: &bucketName,
ObjectName: &objectname,
}
response, err := client.GetObject(ctx, request)
if err != nil {
return nil, fmt.Errorf("failed to retrieve object : %w", err)
}
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(response.Content)
if err != nil {
return nil, fmt.Errorf("failed to read content from object on OCI : %w", err)
}
return buf.Bytes(), nil
}
이 응용 프로그램을 실행하면 object-organizer.go를 실행하여 출력 결과가 표시됩니다.
Namespace : idtwlqf2hanz
created bucket : go-bucket
Put object welcome.txt in bucket go-bucket
Object read from OCI Object Storage contains this content: We would like to welcome you in our humble dwellings. /n We consider it a great honor. Bla, bla.
이전 섹션에서는 SDK를 통해 OCI 서비스와 상호 작용하는 모든 Go 애플리케이션에 대해 설명했습니다. Go의 OCI Functions에 대해 더 자세히 설명해야 할 사항은 무엇입니까? 읽으십시오. 개발 중인 Go 코드 및 Go SDK로 작업하려는 Go 코드가 OCI 함수로 배포되거나 OCI의 컴퓨트 인스턴스에서 실행될 때 수명이 더 단순해질 수 있습니다. 이 경우 리소스 주체 인증(함수의 경우) 및 인스턴스 주체 인증(컴퓨트 인스턴스에서 실행되는 코드의 경우)을 활용할 수 있습니다. 즉, OCI 구성 파일을 포함할 필요가 없으며 SDK와 통신하는 코드가 조금 더 간단해질 수 있습니다.
리소스 주체 인증에 대한 자세한 내용은 OCI Documentation on Resource Principal Authentication for Functions를 참조하십시오.
이 섹션에서는 object-broker라는 OCI 함수에 대해 설명합니다. 경로 함수/object-broker에서 이 문서의 소스 저장소를 찾을 수 있습니다. 이전과 마찬가지로 함수는 메타데이터가 있는 func.yaml 파일과 함수와 Fn 프레임워크 간의 링크가 있는 func.go 파일을 사용하여 정의됩니다. go.mod 파일은 함수에 대한 종속성을 정의합니다. OCI Object Storage Service와의 상호 작용 논리는 object-organizer.go 파일에 있습니다. func.go에서 호출되는 공용 func CreateObject를 정의합니다.
CreateObject는 지정된 버킷에 지정된 이름의 객체를 생성합니다. object-organizer.go의 CreateObject 함수에서 첫번째 행이 이 리소스 주체 인증으로 작동하도록 일부 수정을 거쳤습니다. 이제 사용된 auth.ResourcePrincipalConfigurationProvider()는 OCI 구성 파일 및 개인 키를 애플리케이션에 포함할 필요가 없습니다. 코드는 OCI 내에서 실행되고 리소스(함수 또는 DevOps 빌드 서버일 수 있음) 내에서 더 구체적으로 실행되는 것으로 가정합니다. 리소스 주체는 동적 그룹에 포함되어 있고 해당 그룹 멤버쉽에서 권한을 상속하기 때문입니다. 너무 오래 전에, 당신은 이것에 필요한 조치를 취하기위한 지침을 얻을 것이다.
func CreateObject(objectName string, bucketName string, compartmentOCID string) (string, err) {
configurationProvider, err := auth.ResourcePrincipalConfigurationProvider()
if err != nil {
fmt.Printf("failed to get oci configurationprovider based on resource principal authentication : %s", err)
}
objectStorageClient, cerr := objectstorage.NewObjectStorageClientWithConfigurationProvider(configurationProvider)
func.go 옆에 주의를 기울이겠습니다. Func(tion) myHandler는 함수 트리거를 처리합니다. CreateObject를 호출하지만, 요청이 생성해야 하는 객체의 이름과 객체를 포함할 버킷의 버킷 이름을 결정하기 전에는 호출하지 않습니다. 이러한 이름에는 기본값이 있지만 함수는 특정 값을 제공하는 HTTP 요청 질의 매개변수 값을 찾으려고 합니다. 이 작업은 함수에 대한 HTTP 트리거에만 적용되며 fn 호출을 사용하여 수행된 호출에는 적용되지 않습니다.
func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
objectName := "defaultObjectName.txt"
bucketName := "the-bucket"
fnctx := fdk.GetContext(ctx) // fnctx contains relevant elements about the Function itself
fnhttpctx, ok := fnctx.(fdk.HTTPContext) // fnhttpctx contains relevant elements about the HTTP Request that triggered it
if ok { // an HTTPContent was found which means that this was an HTTP request (not an fn invoke) that triggered the function
u, err := url.Parse(fnhttpctx.RequestURL())
......
특히 예제의 Documentation for Project Fn Go FDK에서 Fn 컨텍스트에 대한 세부정보를 검사할 수 있습니다.
함수는 버킷이 상주해야 하는 OCI 컴파트먼트를 알아야 합니다. 이러한 런타임 설정은 일반적으로 구성을 통해 응용 프로그램의 기능에 정의됩니다. 다음 행과 같이 구성 값은 컨텍스트의 맵에서 함수로 읽을 수 있습니다.
if compartmentOCID, ok := fnctx.Config()["compartmentOCID"]; ok {
Fn CLI를 사용하여 함수 빌드 및 배치
Fn CLI가 설치되어 있고 현재 디렉토리가 functions/object-broker인 로컬 개발 환경의 터미널에 있다고 가정하면 상세 정보 출력을 사용하여 함수의 로컬 빌드를 수행할 수 있습니다.
fn -v build
빌드가 좋아 보이면 다음 단계는 함수를 배치하는 것입니다. Fn 컨텍스트가 go-on-OCI 컨텍스트를 사용하도록 설정된 경우(fn 목록 컨텍스트로 확인) 함수를 OCI의 go-on-OCI-app 애플리케이션에 배치합니다.
fn -v deploy --app go-on-oci-app
컴파트먼트 OCID 값에 대한 구성이 정의된 경우에만 함수가 의미 있는 작업을 수행할 수 있습니다. 콘솔을 통해 또는 Fn CLI에서 다음 명령문을 사용하여 이 작업을 수행할 수 있습니다.
fn cf f go-on-oci-app object-broker compartmentOCID
이제 함수가 배치되고 해당 구성이 있습니다. 이 명령으로 함수 호출에 성공할 것으로 예상할 수 있습니다.
fn invoke go-on-oci-app object-broker
그러나 처리해야 할 마지막 측면은 하나입니다. 함수는 OCI Object Storage Service API를 사용하여 버킷 및 객체를 조작하지만, 이를 위해 명시적으로 권한을 부여받아야 합니다! 이를 위해 동적 그룹과 두 가지 정책을 사용합니다.
객체 및 버킷을 조작하는 함수에 대한 권한
동적 그룹을 사용하여 배치 파이프라인 및 빌드 파이프라인을 나타내는 피부여자를 생성한 것처럼 권한을 부여할 함수가 포함된 동적 그룹도 생성해야 합니다. 동적 그룹을 만들려면 검색 도구 모음에 dyn을 입력합니다. 검색 결과 창에서 동적 그룹 링크를 누릅니다.
동적 그룹에 대한 개요 페이지에서 [동적 그룹 생성]을 누릅니다.
배치 파이프라인에 대한 동적 그룹 이름(예: functions-in-go-on-oci)을 입력하고 선택적으로 설명을 입력합니다. 컴파트먼트의 일부인 함수를 모두 선택하는 다음 규칙을 정의합니다.
All {resource.type = 'fnfunc', resource.compartment.id = ''}
물론
콘솔에서 정책을 생성하려면 검색 도구 모음에 poli를 입력하고 검색 결과 팝업의 서비스 영역에서 Policies > Identity를 누릅니다. 현재 컴파트먼트의 [정책 개요] 페이지로 이동합니다.
첫번째 정책 문은 함수가 컴파트먼트의 객체를 관리할 수 있는 권한을 정의합니다. 두번째 명령문은 버킷 관리 권한을 추가합니다. 이름, 설명 및 다음 명령문을 정의합니다.
allow dynamic-group functions-in-go-on-oci to manage objects in compartment go-on-oci
allow dynamic-group functions-in-go-on-oci to manage buckets in compartment go-on-oci
다음 그림은 해당 명령문을 포함하는 정책이 저장될 때 함수에 적용되는 권한을 보여줍니다.
이제 함수를 호출할 수 있으며 버킷 및 객체에 대한 기본 이름을 사용하여 함수를 실행할 수 있어야 합니다.
fn invoke go-on-oci-app object-broker
버킷이 생성되었으며 OCI URL에서 버킷 페이지까지 콘솔을 사용하여 새로 생성된 객체가 포함되어 있는지 확인합니다.
트리거 함수에 대한 API 게이트웨이의 경로 추가
어디서나 HTTP를 통해 객체 브로커 함수를 호출할 수 있도록 API 게이트웨이를 다시 사용합니다. 콘솔의 검색 표시줄에 gat를 입력합니다. >Gateways > API Management를 누릅니다. the-api-gateway에 대한 링크를 누릅니다. Deployments를 누릅니다. 단일 배치가 포함된 배치가 있는 목록에서 myserver-api 링크를 누릅니다.
[편집]을 눌러 배치 사양을 엽니다. 두번째 단계인 Routes에 대한 링크를 누릅니다. 아래로 스크롤하고 + 다른 경로를 클릭합니다.
이 새 경로의 경로로 /object-broker를 입력합니다. 메소드로 GET을 선택하고 백엔드의 유형으로 Oracle Functions를 선택합니다. 응용 프로그램 go-on-oci-app을 선택한 다음 Function Name을 object-broker로 설정합니다. [다음]을 누른 다음 [변경 사항 저장]을 눌러 변경 사항을 적용하고 새 경로를 실제 경로로 설정합니다.
이제 HTTP 소비자에서 API 게이트웨이에서 함수로 구성되고 최종 버킷 및 객체는 다음과 같이 표시됩니다.
다음 명령을 사용하여 브라우저에서 함수를 호출하거나 명령행에서 curl을 사용합니다.
curl -X "GET" "http:///my-api/object-broker?objectName=new-exciting-object.txt&bucketName=the-ultimate-collection"
자동화된 구축 및 배포
이 함수 object-broker는 Fn CLI를 사용하여 명령줄에 수동으로 배치되었습니다. 그것은 물론 잘 작동했습니다. 하지만 이 기능을 개발하여 여러 개발 주기를 거치게 되면 빌드 및 배포 프로세스에서 자동화를 도입할 수 있습니다.
이전과 마찬가지로 OCI DevOps에서 필요한 요소를 쉽게 설정하여 배포(컨테이너 이미지 레지스트리의 함수 컨테이너 이미지) 및 빌드(코드 저장소에서 시작하여 함수에 대해 새로 구운 컨테이너 이미지 생성)를 위한 자동화된 파이프라인을 달성할 수 있습니다. 함수와 관련된 기본 요소는 빌드 파이프라인의 관리형 빌드 단계에 대한 빌드 사양 파일입니다. 이 파일은 func.go 및 func.yaml와 동일한 디렉토리에 go-function-build-spec.yaml으로 제공됩니다.
함수 컨테이너 이미지에 대한 DevOps 아티팩트, 함수에 대한 환경 및 빌드 및 배치에 대한 두 파이프라인을 생성한 후 자동화된 DevOps 프로세스 설정은 다음과 같습니다.
이 문서의 한 가지 중점 영역은 Go로 작성되고 Oracle Cloud Infrastructure에서 실행되는 서버리스 기능이었습니다. 외부 HTTP 소비자에게 함수에 대한 액세스를 제공하기 위해 API 게이트웨이를 사용하는 것과 마찬가지로 이러한 함수의 자동 빌드 및 배치에 대해 설명했습니다.
두 번째 주요 주제는 Go 애플리케이션의 OCI 서비스와 상호 작용하기 위한 Go SDK for OCI였습니다. 이 문서에서는 Go 코드를 사용하여 오브젝트 스토리지 서비스에 접근하여 파일을 저장하고 검색하는 방법을 보여주었습니다.
두 주제는 함수 객체 브로커에서 결합되었습니다. 이 OCI 함수는 동적 그룹을 통해 부여된 리소스 주체 인증 및 권한을 활용합니다. 런타임 구성을 통해 함수는 현재 환경 특정 설정에 대해 학습합니다.
다음 기사에서는 Oracle Database와 상호 작용하는 것이 주요 주제가 될 것입니다. Go 애플리케이션에서 로컬 Oracle Database로의 연결 및 OCI에서 실행되는 Autonomous Database로의 연결을 생성하고 Go 애플리케이션의 편안함에서 이러한 데이터베이스로 SQL 작업을 수행합니다. 추가 항목에는 배포 프로세스의 전자 지갑을 포함하여 데이터베이스 인증서를 적절히 관리하기 위한 Oracle Wallet 작업, 단일 애플리케이션에서 OCI Object Storage 및 Autonomous Database 서비스와의 상호 작용 결합이 포함됩니다.