1. 목표
Terraform으로 인프라 구성 시간을 줄여보자
Cloud Run은 Google Cloud의 대표적인 Serverless 서비스이다. Serverless는 서버가 없다는 것은 아니고 해당 VM 처럼 서버의 운영 또는 관리할 필요가 없기 때문에 해당 의미를 강조해서 Serverless 라는 용어를 사용한다. Cloud Run은 컨테이너 기반으로 서비스를 제공한다는 장점, Cloud Functions 보다 timeout의 제약이 덜하다는 장점을 가진다. 그래서 간단한 App을 띄워 Test를 위해서도 사용되고 Production 환경에서도 종종 사용한다.
실제 업무를 하다보면 컨테이너 이미지를 Cloud Run으로 띄워 사용하는 경우가 많다. 위 그림 처럼 서버리스 앱의 전역 외부 HTTP(S) 부하 분산을 연결하여 구성한다. 위 구성을 하기 위해 SSL 구성, 서버리스를 백엔드로 구성해야하는 부분 등 고려해야하는 부분이 많아 시간을 많이 잡아먹었다.
이 반복되는 작업을 Terraform을 사용해서 apply 한번으로 제공하면 좋겠다는 생각으로 과제를 시작했다.
2. 작업내역
2.1 사전작업
이 작업은 프로젝트가 생성되어 있고, Cloud Shell을 사용하여 구성한다.
- 프로젝트 생성
- Cloud Shell 가동
- Install Terraform (Cloud Shell에는 기본적으로 설치 되어있음)
2.2 배포환경 구성
프로젝트를 생성하고 프로젝트 ID를 변수 값에 할당해준다.
$ PROJECT=study-terraform-ygpark
프로젝트를 세팅 해주고, 로그인 해준다.
$ gcloud config set project ${PROJECT}
Updated property [core/project].
$ gcloud auth application-default login
$ export GOOGLE_PROJECT=$(gcloud config get-value project)
Your active configuration is: [cloudshell-12028]
사용되는 서비스의 api를 enable 한다.
- Cloud Run Admin
- Compute Engine API
$ gcloud services enable run.googleapis.com compute.googleapis.com
2.3 Terraform code 구성
- main.tf: 실제 infra를 구성하는 파일
- outputs.tf: Output values 란 모듈에서 return하는 값으로 다른 모듈에서 그 값을 다양하게 사용할 수 있다.
- variables.tf: 입력 변수 정의 후 구성 관리
- versions.tf: providers의 버전을 명시, 반복 배포시 동일한 버전을 사용할 수 있도록 한다.
2.3.1 project_id
project_id 변수를 만들어 놓고 이후 apply할 때 입력하여 넣어주거나 지정할 수 있다.
provider "google" {
project = var.project_id
}
provider "google-beta" {
project = var.project_id
}
variables.tf의 project_id 변수
variable "project_id" {
type = string
}
2.3.2 Cloud Run
image는 Google Cloud에서 제공하는 기본 이미지를 사용한다. location, project는 변수를 가져오고, annotations에 모든 사람이 Access 가능하도록 설정해준다.
resource "google_cloud_run_service" "default" {
name = "example"
location = var.region
project = var.project_id
template {
spec {
containers {
image = "gcr.io/cloudrun/hello"
}
}
}
metadata {
annotations = {
# For valid annotation values and descriptions, see
# https://cloud.google.com/sdk/gcloud/reference/run/deploy#--ingress
"run.googleapis.com/ingress" = "all"
}
}
}
annotations의 "run.googleapis.com/ingress"에서 서비스를 호출할 수 있는 인그레스 트래픽 소스를 설정한다.
- all: default, 모든 소스의 인바운드 요청이 허용된다.
- internal: Cloud Run(완전 관리형)의 경우 동일한 프로젝트 또는 VPC 서비스 제어 경계에 있는 VPC 네트워크의 인바운드 요청과 동일한 프로젝트 또는 VPC 서비스 제어 경계에 있는 Pub/Sub 구독 및 Eventarc 이벤트만 허용된다. 다른 모든 요청은 거부된다.
- internal-and-cloud-load-balancing: Cloud Run(완전 관리형)에서만 지원된다. Google Cloud Load Balancing 또는 내부 옵션에서 허용하는 트래픽 소스의 인바운드 요청만 허용된다.
allUsers에 대해 Cloud Run에 접근할 수 있도록 호출 권한도 부여한다.
resource "google_cloud_run_service_iam_member" "public-access" {
location = google_cloud_run_service.default.location
project = google_cloud_run_service.default.project
service = google_cloud_run_service.default.name
role = "roles/run.invoker"
member = "allUsers"
}
- allUsers: Google 계정 유무에 관계없이, 인터넷에 있는 모든 사람을 나타내는 특수 식별자이다.
- roles/run.invoker: Cloud Run을 호출 할 수 있도록 하는 역할이다.
생성이 되면 콘솔에서 확인 할 수 있다.
2.3.3 서버리스 NEGs
서버리스 서비스들은 독립적인 VPC 네트워크에 존재한다. 이 서비스들을 로드벨런서의 백엔드로 사용하려면 서버리스 NEG를 사용하여 연결해줘야 한다. 서버리스 NEGs는 App Engine, Cloud Functions 또는 Cloud Run 서비스를 외부 로드벨런서와 연결할 수 있도록 하는 백엔드이다.
이 백엔드에 위에서 구성한 Cloud Run을 붙여준다.
resource "google_compute_region_network_endpoint_group" "serverless_neg" {
provider = google-beta
name = "serverless-neg"
network_endpoint_type = "SERVERLESS"
region = var.region
cloud_run {
service = google_cloud_run_service.default.name
}
}
2.3.4 HTTP(s) LB
Google Cloud의 serverless_negs 모듈을 가져와 사용한다. Classic HTTP(s) LB 생성할 때 ssl구성을 할 수 있다. ssl에서 구글이 제공하는 인증서를 사용하도록 설정한다. backends는 위에서 구성한 서버리스 NEG를 붙여준다.
module "lb-http" {
source = "GoogleCloudPlatform/lb-http/google//modules/serverless_negs"
version = "~> 6.3"
name = var.lb_name
project = var.project_id
ssl = var.ssl
managed_ssl_certificate_domains = [var.domain]
https_redirect = var.ssl
labels = { "example-label" = "cloud-run-example" }
backends = {
default = {
description = null
groups = [
{
group = google_compute_region_network_endpoint_group.serverless_neg.id
}
]
enable_cdn = false
security_policy = null
custom_request_headers = null
custom_response_headers = null
iap_config = {
enable = false
oauth2_client_id = ""
oauth2_client_secret = ""
}
log_config = {
enable = false
sample_rate = null
}
}
}
}
variables.tf 에 변수를 담아 사용한다. default 설정이 없다면 apply 시에 "-var=project_id={프로젝트 이름}" 와 같이 변수를 같이 입력해줘야한다.
variables.tf
variable "project_id" {
type = string
}
variable "region" {
description = "Location for load balancer and Cloud Run resources"
default = "us-central1"
}
variable "ssl" {
description = "Run load balancer on HTTPS and provision managed certificate with provided `domain`."
type = bool
default = true
}
variable "domain" {
description = "Domain name to run the load balancer on. Used if `ssl` is `true`."
type = string
}
variable "lb_name" {
description = "Name for load balancer and associated resources"
default = "tf-cr-lb"
}
2.3.5 Input 값과 Output 정리
Inputs
Name | Description | Type | Default | Required |
domain | 로드 밸런서를 실행할 도메인 이름, ssl이 true인 경우 사용 |
string | n/a | yes |
lb_name | 로드 밸런서 및 관련 리소스의 이름 | string | "tf-cr-lb" | no |
project_id | n/a | string | n/a | yes |
region | 부하 분산기, Cloud Run리소스의 위치 | string | "us-central1" | no |
ssl | HTTPS에서 로드 밸런서를 실행하고 제공된 도메인으로 관리형 인증서를 프로비저닝 | bool | true | no |
output
Name | Description |
load-balancer-ip | n/a |
2.4 배포
2.4.1 초기화
$ terraform init
Initializing modules...
Downloading registry.terraform.io/GoogleCloudPlatform/lb-http/google 6.3.0 for lb-http...
- lb-http in .terraform/modules/lb-http/modules/serverless_negs
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/random...
- Finding hashicorp/google-beta versions matching ">= 3.53.0, < 5.0.0"...
- Finding hashicorp/google versions matching ">= 3.53.0, < 5.0.0"...
- Installing hashicorp/random v3.4.3...
- Installed hashicorp/random v3.4.3 (signed by HashiCorp)
- Installing hashicorp/google-beta v4.45.0...
- Installed hashicorp/google-beta v4.45.0 (signed by HashiCorp)
- Installing hashicorp/google v4.45.0...
- Installed hashicorp/google v4.45.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
2.4.2 검토 및 배포
$ terraform apply -var=project_id=$PROJECT \
-var=domain=example.com
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# google_cloud_run_service.default will be created
+ resource "google_cloud_run_service" "default" {
+ autogenerate_revision_name = false
+ id = (known after apply)
+ location = "us-central1"
+ name = "example"
+ project = "study-terrafom-ygpark"
+ status = (known after apply)
+ metadata {
+ annotations = {
+ "run.googleapis.com/ingress" = "all"
}
...
Plan: 8 to add, 0 to change, 0 to destroy.
다음과 같이 출력되면 검토 후에 yes를 입력해줘 배포를 진행한다.
배포가 완료되면 로드 밸런서의 IP 주소를 출력된다. 이 IP 주소를 가리키도록 도메인의 DNS 레코드를 업데이트하면 DNS로 Cloud Run에 접속할 수 있다.
outputs.tf
output "load-balancer-ip" {
value = module.lb-http.external_ip
}
콘솔에서 Load balancer 구성을 다음과 같이 확인 할 수 있다.
Cloud Run 백엔드에 접속하면 Cloud Run의 정보를 확인 할 수 있다.
5. 참고
- [GCP]Serverless 서비스인 Cloud Run 알아보기 1부 — Cloud Run 개요
- Terraform examples for external HTTP(S) load balancers
- HTTPS load balancer with Serverless NEG backend example (Cloud Run)
- 서버리스 네트워크 엔드포인트 그룹 개요 | 부하 분산 | Google Cloud
- GoogleCloudPlatform/lb-http/google | serverless_negs Submodule | Terraform Registry
'스터디 > Terraform' 카테고리의 다른 글
[Terraform] google Cloud에서 terraform state 파일 관리 (0) | 2022.11.13 |
---|