티스토리 뷰
안녕하세요, GCP의 Google Cloud의 서버리스 제품 중 Google Cloud Functions에 대해 알아보겠습니다.
Cloud Function
Cloud Functions(2세대)는 Google Cloud의 Functions-as-a-Service 제품인 Google Cloud Functions의 다음 버전입니다. 이를 통해 사용자는 동시성, 트래픽 분할, 처리 시간 연장 등 Cloud Run의 주요 이점을 활용할 수 있습니다. 이 새 버전은 Cloud Run 및 Eventarc를 기반으로 하여 성능 및 확장성에 대한 고급 제어 기능을 제공하고 90개가 넘는 이벤트 소스의 함수 런타임 및 트리거에 대한 더 많은 제어 기능을 제공합니다.
Cloud Function 제품을 이해하기 위해 Getting started with Cloud Functions (2nd gen) 코드랩을 참고하였습니다.
이 Codelab에서는 HTTP 호출에 응답하고 Pub/Sub 메시지와 Cloud 감사 로그에 의해 트리거되는 Cloud Functions를 만드는 과정을 안내합니다. 실습에 필요한 사전작업을 진행합니다.
HTTP 요청에 응답하는 인증된 Node.js 함수를 생성합니다.
index.js 파일 생성
const functions = require('@google-cloud/functions-framework');
functions.http('helloWorld', (req, res) => {
res.status(200).send('HTTP with Node.js in GCF 2nd gen!');
});
dependencies를 표기하는 package.json 파일 생성
{
"name": "nodejs-functions-gen2-codelab",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
gcloud 명령어로 함수 deploy
gcloud functions deploy nodejs-http-function \
--gen2 \
--runtime nodejs16 \
--entry-point helloWorld \
--source . \
--region $REGION \
--trigger-http \
--timeout 600s
아래 명령어로 함수 테스트
gcloud functions call nodejs-http-function \
--gen2 --region $REGION
HTTP with Node.js in GCF 2nd gen!
특정 Topic에 게시된 Pub/Sub 메시지에 의해 트리거되는 Python 함수를 생성합니다.
Pub/Sub topic 생성
TOPIC=cloud-functions-gen2-topic
gcloud pubsub topics create $TOPIC
CloudEvent ID가 포함된 메시지를 간단히 기록하는 main.py 파일 생성
import functions_framework
@functions_framework.cloud_event
def hello_pubsub(cloud_event):
print('Pub/Sub with Python in GCF 2nd gen! Id: ' + cloud_event['id'])
dependencies를 표기하는 requirements.txt 생성
functions-framework==3.*
아래 명령어로 함수 deploy
gcloud functions deploy python-pubsub-function \
--gen2 \
--runtime python39 \
--entry-point hello_pubsub \
--source . \
--region $REGION \
--trigger-topic $TOPIC
gcloud pubsub topics publish $TOPIC --message="Hello World"
messageIds:
- '11707454230388048'
Cloud Storage 버킷의 이벤트에 응답하는 Node.js 함수 생성합니다.
Cloud Storage events 에 응답하는 index.js 파일 생성
const functions = require('@google-cloud/functions-framework');
functions.cloudEvent('helloStorage', (cloudevent) => {
console.log('Cloud Storage event with Node.js in GCF 2nd gen!');
console.log(cloudevent);
});
dependencies를 표기하는 package.json 파일 생성
{
"name": "nodejs-functions-gen2-codelab",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
Cloud bucket 생성
export BUCKET="gs://gcf-gen2-storage-$PROJECT_ID"
gsutil mb -l $REGION $BUCKET
함수 deploy
gcloud functions deploy nodejs-storage-function \
--gen2 \
--runtime nodejs16 \
--entry-point helloStorage \
--source . \
--region $REGION \
--trigger-bucket $BUCKET \
--trigger-location $REGION
버킷에 파일 업로드를 통한 함수 테스트
echo "Hello World" > random.txt
gsutil cp random.txt $BUCKET/random.txt
아래 명령어로 로그에서 CloudEvent 수신 확인
gcloud functions logs read nodejs-storage-function \
--region $REGION --gen2 --limit=100 --format "value(log)"
Compute Engine VM 인스턴스가 생성될 때 Cloud 감사 로그 이벤트를 수신하는 Node.js 함수를 생성합니다.
Cloud 감사 로그 기능을 사용하려면 Eventarc에 대한 감사 로그를 활성화해야 합니다. 또한 eventarc.eventReceiver 역할이 있는 서비스 계정을 사용해야합니다
1. Cloud Audit Logs에서 Compute Engine API
기본 Compute Engine 서비스 계정에 eventarc.eventReceiver IAM 역할 부여
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--role roles/eventarc.eventReceiver
index.js
- CloudEvent로 래핑된 감사 로그를 수신하는 애플리케이션 코드
- 그런 다음 Compute Engine VM 인스턴스 세부정보를 추출하고 VM 인스턴스에 라벨 설정
const { google } = require("googleapis");
var compute = google.compute("v1");
exports.labelVmCreation = async (cloudevent) => {
var data = cloudevent;
// in case an event has >1 audit log
// make sure we respond to the last event
if (!data.operation.last) {
console.log("Operation is not last, skipping event");
return;
}
// projects/dogfood-gcf-saraford/zones/us-central1-a/instances/instance-1
var resourceName = data.protoPayload.resourceName;
var resourceParts = resourceName.split("/");
var project = resourceParts[1];
var zone = resourceParts[3];
var instanceName = resourceParts[5];
var username = data.protoPayload.authenticationInfo.principalEmail.split("@")[0];
console.log(`Setting label username: ${username} to instance ${instanceName} for zone ${zone}`);
var authClient = await google.auth.getClient({
scopes: ["https://www.googleapis.com/auth/cloud-platform"]
});
// per docs: When updating or adding labels in the API,
// you need to provide the latest labels fingerprint with your request,
// to prevent any conflicts with other requests.
var labelFingerprint = await getInstanceLabelFingerprint(authClient, project, zone, instanceName);
var responseStatus = await setVmLabel(
authClient,
labelFingerprint,
username,
project,
zone,
instanceName
);
// log results of setting VM label
console.log(JSON.stringify(responseStatus, null, 2));
};
async function getInstanceLabelFingerprint(authClient, project, zone, instanceName) {
var request = {
project: project,
zone: zone,
instance: instanceName,
auth: authClient
};
var response = await compute.instances.get(request);
var labelFingerprint = response.data.labelFingerprint;
return labelFingerprint;
}
async function setVmLabel(authClient, labelFingerprint, username, project, zone, instanceName) {
var request = {
project: project,
zone: zone,
instance: instanceName,
resource: {
labels: { "creator": username },
labelFingerprint: labelFingerprint
},
auth: authClient
};
var response = await compute.instances.setLabels(request);
return response.statusText;
}
함수 deploy
gcloud functions deploy gce-vm-labeler \
--gen2 \
--runtime nodejs16 \
--entry-point labelVmCreation \
--source . \
--region $REGION \
--trigger-event-filters="type=google.cloud.audit.log.v1.written,serviceName=compute.googleapis.com,methodName=beta.compute.instances.insert" \
--trigger-location us-central1
Audit Log function를 테스트하기 위해 Compute Engine VM 생성
위와 같이 Cloud Audit Log 이벤트가 발생했을 때 VM에 creator 라벨이 생성된 것을 확인했습니다.
Jenkins 연동
[참고] Jenkins를 사용하여 GCP Cloud Function 테스트 자동화
테스트 주도 개발 프로세스를 따르는 동안 반복적인 테스트를 통해 진행 상황을 추적해야 합니다. 따라서 견고하고 효율적이며 비용 효율적인 자동화 테스트 프레임워크가 없다면 수동으로 페이로드를 트리거하고 결과를 검증해야 합니다. 수동 테스트는 시간이 더 오래 걸릴 뿐만 아니라 오류가 발생하기 쉽습니다. Jenkins를 오케스트레이션 도구로 사용하여 Cloud Function, Cloud Run, Dataflow와 같은 이벤트를 처리하는 GCP 구성 요소를 테스트하는 데 사용할 수 있습니다.
Jenkins Pipeline
https://www.jenkins.io/doc/book/pipeline/getting-started/
GCP와 Jenkins 설정
https://dareplanet.tech/en/insights/how-to-configure-jenkins-with-google-cloud-platform/
Google Cloud Platform에서 Jenkins를 설정하기 위한 요구사항
- Account on a Jenkins instance*: With administrator permissions.
- Account on Google Cloud Platform: Capable of using Compute Engine and create service accounts.
- Optional: gcloud command-line tool.
Google Cloud Platform 서비스 계정 만들기
gcloud iam service-accounts create jenkins-gce
서비스 계정에 필요한 역할 할당
export PROJECT=$(gcloud info --format='value(config.project)')
export SA_EMAIL=$(gcloud iam service-accounts list --filter="name:jenkins-gce" \
--format='value(email)')
gcloud projects add-iam-policy-binding --member serviceAccount:$SA_EMAIL \
--role roles/compute.instanceAdmin $PROJECT
gcloud projects add-iam-policy-binding --member serviceAccount:$SA_EMAIL \
--role roles/compute.networkAdmin $PROJECT
gcloud projects add-iam-policy-binding --member serviceAccount:$SA_EMAIL \
--role roles/iam.serviceAccountUser $PROJECT
gcloud projects get-iam-policy $PROJECT
JSON 서비스 계정 키 가져오기
gcloud iam service-accounts keys create --iam-account $SA_EMAIL jenkins-gce.json
Cloud Functions 생성
Cloud Storage 내 Cloud Functions 소스 경로 확인
Google Compute Engine(GCE) 플러그인 설치
Manage Jenkins > Manage Plugins > Available and look for “Google Compute Engine”
Google Compute Engine 플러그인 설치
Service account credentials setup
Manage Jenkins > Manage Credentials > Global > Add Credentials of kind “Google Service Account from private key”.
-> Google Service Account from private key 로 에러 발생 시 아래와 같이 Secret file로 등록해줍니다.
Jenkins Pipeline 실행
Groovy 파일 생성
pipeline {
agent any
stages {
stage('Deploy to Cloud Functions') {
steps {
withCredentials([file(credentialsId: '${Service Account Credential Name}', variable: 'GCP_SA_KEY')]) {
sh 'gcloud auth activate-service-account --key-file=$GCP_SA_KEY'
sh 'gcloud config set project ${PROJECT_ID}'
sh 'gcloud functions deploy {FUNCTIONS_NAME} --gen2 --runtime=python312 --region=asia-northeast3 --entry-point=hello_http --trigger-http --source=${Cloud Functions Source Directory}'
}
}
}
}
}
${Service Account Credential Name} : Jenkins Credentials에 등록한 GCP Service Account Credential 이름
${Project_ID} : 배포할 GCP 프로젝트의 ID
${FUNCTIONS_NAME} : 배포할 Cloud Functions 이름
${Cloud Functions Source Directory} : Cloud Functions 소스 경로
Build Test
Cloud Function 트리거 확인
참고
https://dareplanet.tech/en/insights/how-to-configure-jenkins-with-google-cloud-platform/
https://cloud.google.com/functions/docs/deploy?hl=ko
ERROR: (gcloud.functions.deploy) Invalid value for [--source]: Provided source directory does not have file [package.json] which is required for [nodejs20]. Did you specify the right source?
https://github.com/quarkusio/quarkus/issues/38371
How to Deploy GCP Cloud Functions with Cloud Build
https://levelup.gitconnected.com/how-to-deploy-gcp-cloud-functions-with-cloud-build-a35e6010da33
ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Permission 'cloudfunctions.functions.get' denied on 'projects/kbshare-security/locations/asia-northeast3/functions/gcp-test']
'IT > Infra&Cloud' 카테고리의 다른 글
[gcp] Cloud Identity SSO 설정 (0) | 2024.07.15 |
---|---|
[gcp] Cloud Run (0) | 2024.07.13 |
[gcp] Serverless service(Cloud Function vs Cloud Run) (0) | 2024.07.09 |
[gcp] Network Connectivity Center(with Lab: NCC) (0) | 2024.07.07 |
[gcp] Cloud VPN (0) | 2024.07.02 |
- Total
- Today
- Yesterday
- AWS
- operator
- SDWAN
- 국제 개발 협력
- security
- 파이썬
- cloud
- k8s
- gcp serverless
- IaC
- VPN
- PYTHON
- NW
- k8s calico
- cni
- 혼공단
- handson
- EKS
- 혼공챌린지
- S3
- k8s cni
- 도서
- GKE
- AI
- controltower
- NFT
- OS
- terraform
- GCP
- 혼공파
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |