[GCP] Cloud Scheduler를 이용한 주기적 작업 실행 공부/CLOUD

Date 2022. 1. 6. 14:06

클라우드를 포함한 여러 시스템들은 주기적으로 작업을 실행하게 해주는 기능들을 제공해준다.

 

리눅스에는 crontab을 이용해서 수행할 수 있고, AWS에서는 Cloudwatch Events를 이용해서 비슷한 기능을 수행할 수 있다.

마찬가지로 kubernetes는 CronJob이라는 리소스를 이용해서 주기적 작업을 수행할 수 있다.

 

비슷하게 구글 클라우드에서는 Cloud Scheduler라는 서비스를 통해 주기적 작업을 수행할 수 있다.

 

Cloud Scheduler 특징

구글 클라우드에서 제공하는 Cloud Scheduler는 다음과 같은 특징을 갖고 있다.(공식 홈페이지 참조)

 

1. 대부분의 클라우드 서비스가 그렇듯 구글 클라우드에서 제공하는 로깅 서비스와 자동으로 연동된다.

2. 작업 대상으로 HTTP 요청을 제공한다. 즉 HTTP 엔드포인트가 열려있는 곳이면 뭐든지 호출할 수 있다.

3. 작업 대상으로 구글 클라우드의 Pub/Sub을 대상으로 설정할 수 있다. 이를 통해서 해당 topic을 Subscribe하고 있는 다른 리소스들에 작업을 수행하게 할 수 있다.

4. retry 정책을 설정 가능하다. exponential backoff 등을 설정할 수 있다.

 

또한 최대 3개까지의 작업은 무료로 생성 가능하다고 한다. 

 

Cloud Scheduler 생성

 

주기적으로 HTTP 요청을 날리는 작업을 생성할 것이다. API는 모두 활성화 되어 있고 필요한 IAM 또한 할당되어 있다고 가정한다.

또한 여기서는 클라우드 콘솔(GUI)를 이용하여 생성했다.

 

1. 작업 정의

 

 

작업의 이름과, 시간대를 설정할 수 있다.

또한 빈도는 unix-cron 형식을 이용해 설정 가능하다.

 

2. HTTP 요청 구성

 

 

작업을 할 때 전송할 HTTP 요청을 구성한다.

 

기본적인 헤더, 바디를 설정할 수 있고

추가적으로 헤더에 인증을 위해 해당 작업을 수행하는 서비스 계정 정보를 담아 보낼 수 있다.

 

여기서는 작업용으로 생성한 Cloud Run에 요청을 보내기 위해서 OIDC 토큰을 함께 보내 Cloud Run 인증을 수행하도록 하였다.

 

3. 기타 configuration

 

재시도 횟수, backoff 타임 등을 설정할 수 있다. 

 

여기까지 완료되었으면 생성이 완료되었다. 주기에 상관없이 콘솔을 통해 직접 호출할 수 있다.

 

이후 작업 결과는 구글 클라우드의 Cloud Logging을 통해서 확인할 수 있다.

 

로그

 

HTTP의 경우 요청을 보내면서 AttempStarted 로그가 찍히고, 

요청에 대한 응답이 2xx 이면 AttemptFinished 로그가 찍히는걸 볼 수 있다.

Terraform 오버뷰 - GCP Cloud Run 배포하기 공부/CLOUD

Date 2021. 8. 16. 16:29

테라폼이란

클라우드의 인프라를 선언적(declaritve)으로 관리할 수 있게 해주는 IaC(Infrastructur as Code) 오픈소스 소프트웨어이다.

 

다시 풀어서 말하면 클라우드의 리소스(EC2의 경우 ami, instance type, GCP Cloud Run의 경우 컨테이너의 spec 등..)을

1) 선언적 2) 소스코드로 관리 할수 있는 소프트웨어라 할 수 있다.

 

이러한 IaC 툴을 이용하면 기존에 리소스를 CLI/ 콘솔 등으로 관리할때 보다 다양한 장점을 가져갈 수 있다.

 

1) 기존 방식인 콘솔 또는 CLI(API call) 을 통해 클라우드 리소스에 접근하는거와 달리 Code로 관리함으로써 클라우드 인프라에 대한 버전관리를 할 수 있다.(git 등 이용)

2) 코드로 관리하기 때문에 같은 인프라를 여러번 복제 하는 등 쉽게 인프라를 배포할 수 있다.

 

리소스 배포하기

가장 먼저 클라우드 리소스에 접근할 수 있는 API Key가 필요하다. GCP를 사용했고 json 형식의 키를 발급받아 사용했다.

1) Configuration

우선 테라폼 CLI를 설치해야 한다. 단일 바이너리 파일로 설치되므로 편리하다.

 

sudo apt-get update && sudo apt-get install -y gnupg software-properties-common curl

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -

sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"

sudo apt-get update && sudo apt-get install terraform

 

다음은 테라폼에 대한 Configuration을 해주어야 한다. 폴더를 생성하고 key file을 가져온 뒤 main.tf를 수정한다.

 

cd terraform
cp JSON_KEY ./key.json

vi main.tf

terraform {
  required_providers {
    google = {
      source = "hashicorp/google"
      version = "3.5.0"
    }
  }
}

provider "google" {
  credentials = file("key.json")

  project = "PROJECT"
  region  = "REGION"
  zone    = "ZONE"
}

GCP를 기준으로 했으며 PROJECT, REGION, ZONE을 적절히 입력한다.

 

이제 테라폼 CLI를 이용해 프로젝트를 초기화한다.

 

terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/google from the dependency lock file
- Installing hashicorp/google v3.5.0...
- Installed hashicorp/google v3.5.0 (signed by HashiCorp)

 

2) Write

이제 배포할 리소스에 대한 선언이 필요하다. 간단한 Cloud Run 컨테이너를 배포한다.

 

vi cloudrun.tf

resource "google_cloud_run_service" "default" {
  name     = "cloudrun-srv"
  location = "asia-northeast1"

  template {
    spec {
      containers {
        image = "us-docker.pkg.dev/cloudrun/container/hello"
      }
    }
  }

  traffic {
    percent         = 100
    latest_revision = true
  }
}

 

Terraform Registry 에서 배포 가능한 리소스들의 정보를 알 수 있다.

 

3) Apply

terraform apply를 통해 기존 state와 리소스들을 비교하며 업데이트를 수행한다.

 

terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

...

 

4) 결과 확인

 

terraform show 명령어는 현재 state를 보여준다. 

 

terraform show

resource "google_cloud_run_service" ...

terraform show | grep url

url = "https://cloudrun-srv-ㅁㅁ-an.a.run.app"

// 컨테이너 cold start로 응답 지연될 수 있음
// IAM Policy를 설정해주지 않아 Forbidden을 반환합니다.
curl https://cloudrun-srv-ㅁㅁ-an.a.run.app
...

 

쓰면서 느낀 점

일단 쉽게 리소스를 배포할 수 있다는 뚜렷한 장점이 있다. 또한 테라폼 공식 페이지가 굉장히 잘나와있고 레퍼런스가 많아 참고할 자료가 많다.

 

반면에 불편한 점들도 존재한다.

기존에 있던 리소스를 테라폼으로 관리하기 위해서는 terraform import 를 통해 불러와야 하는데,

 

state만 업데이트 하고 configuration은 관리해주지 않는다. 손으로 한땀한땀 tf 파일을 수정해줘야 한다.

이를 위해 terraforming이나 terraformer 등의 도구가 존재하지만 완벽하지는 않아서 직접 수정해야 할 필요가 있다.

 

또한 테라폼 자체의 단점은 아니지만 테라폼으로 생성한 리소스를 기존 방식인 CLI등으로 수정하면 당연히 state와 어긋나게 된다. 이를 맞추려면 terraform taint나 terraform apply -replace를 통해 state를 맞춰줘야 할 필요가 있다.

[k8s] Service 리소스 Overview (2) : Ingress와 Health check 공부/CLOUD

Date 2021. 8. 15. 17:34

저번 글에 이어 Ingress와 Health check를 정리했다.

Ingress

  • 쿠버네티스 Ingress 리소스를 통해 HTTP 트래픽을 여러 Service 로 전달할 수 있다.
  • 우선 실제로 트래픽을 보고 처리해야 하는 Ingress Controller 가 필요하다. 대표적으로 오픈소스 웹서버인 nginx 구현체인 Nginx Ingress Controller 가 존재한다.
  • https://kubernetes.io/ko/docs/concepts/services-networking/ingress-controllers/
    • 구글의 쿠버네티스 서비스인 GKE 는 자체적으로 구현한 ingress-gce 가 존재한다.
  • 접근하는 트래픽에 대해 어떻게 처리할지에 대해서 관리하는게 Ingress 리소스이다.
 

인그레스 컨트롤러

인그레스 리소스가 작동하려면, 클러스터는 실행 중인 인그레스 컨트롤러가 반드시 필요하다. kube-controller-manager 바이너리의 일부로 실행되는 컨트롤러의 다른 타입과 달리 인그레스 컨트롤러

kubernetes.io

 

  • metadataannotations 를 이용해 인그레스 오브젝트에 대한 옵션을 설정할 수 있다.
    • nginx 의 경우 nginx.ingress.kubernetes.io/rewrite-target 같은 옵션이 존재한다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-test
  annotations:
  ...
spec:
  rules:
    - host: test.example.com
    http:
        paths:
        - path: /test
            backend:
                service:
                    name: test
                    port:
                        number: 80

 

  • Ingress 리소스의 경우 Ingress Controller 가 받는 트래픽 중
    • 요청의 Host 헤더가 test.example.com 인 요청에 대해 test 서비스의 80 포트로 보내진다.
  • 하나의 Ingress 에 다양한 rulespath 를 사용할 수 있다.
    • GCP 에서 사용하는 Cloud Load Balacerurl map 이란 리소스가 해당 역할을 담당한다.
      • ingress-gce 레포에 pkg/loadbalancer/url_maps 로 확인할 수 있다.

Ingress TLS

  • Ingress Controller 는 HTTPS 트래픽을 받아 TLS Connection 을 열고 백엔드에 위치한 서비스들에는 HTTP 트래픽으로 전송한다.(Terminate TLS)
  • TLS 연결에 사용되는 서버 인증서는 발급받은 뒤 Secret 리소스를 사용하여 저장할 수 있다.
openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj \
CN=test.example.com

kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key

 

  • 또는 CSR 을 생성해서 CertificateSigningRequest 리소스를 통해 발급받아도 된다고 한다.
kind: Ingress
...
spec:
    tls:
    - hosts: 
        - test.example.com
        secretName: tls-secret
...

 

annotationnginx.gress.kubernetes.io/ssl-redirect 기본값은 True 다. 즉 HTTP 로 요청을 보내도 tls 가 존재하면 HTTPS 로 리다이렉트한다.

Health check

  • ServicelabelSelector 에 맞는 Pod 들은 자동으로 서비스의 Endpoint 리소스로 등록된다. 하지만 Pod 가 생성된 뒤 Configuration이 필요하거나 등의 warm-up 절차가 있다면 Service 는 해당 Pod 로 요청을 보내서는 안될것이다. 이를 위해 Readiness Probe가 존재한다.

Readiness Probes

  • Pod 가 클라이언트의 요청을 받아들일 수 있는지 확인하기 위해 존재한다.
  • 주기적으로 호출되어 Pod 가 요청을 받을 수 있는지 확인한다.
  • Container 마다 요청을 받을 수 있다는 상태는 다르다. 쿠버네티스는 3가지 종류를 지원한다.
    • HTTP GET probe : 요청을 보내 HTTP Status code를 보고 확인한다.
    • TCP Socket : 컨테이너의 특정 port로 소켓을 오픈한다. Established 면 Ready 상태.
    • Exec probe : 컨테이너에서 프로세스를 실행해 Exit status code를 참조한다.
  • Liveness Probe 와 달리 실패해도 Pod를 재시작하지는 않는다.

[k8s] Service 리소스 Overview (1) 공부/CLOUD

Date 2021. 8. 14. 19:26

클러스터 내부에서든 외부에서든 실제 Workload를 받는 부분인 Pod에 접근하기 위해서는 Pod의 IP정보+ port를 알아야 한다.

 

Replication Controller가 조정할 수도 있고 Node가 죽어서 다른 Node 로 파드를 옮기는 등 쿠버네티스에서 Pod라는 리소스는 항상 죽을 수 있다. 즉 Pod를 식별하는 IP는 계속 변경된다.

 

이런 문제를 해결하기 위해서 Pod에 접근하는 고정된 IP가 필요한데, 이를 담당하는 오브젝트가 바로 Service 이다.

 

서비스는 리소스가 살아있는 한 고정된 IP를 가지고 있으며, TCP/UDP 패킷을 Pod로 Redirect 해준다.

Service의 작동방식

우선 어떤 Pod로 트래픽을 분산할지 Pod를 찾아야 한다. Pod를 찾는 방법은 labelSelector가 있다. (다른 방법이 있을 수 있음~?)

 

우선 해당 Selector를 만족하는 Pod들을 찾는다. 또한 그 Pod의 IP를 이용해 Endpoint 리소스(IP:ContainerPort)를 생성한다.

 

EndPoint 리소스들은 서비스에 붙게되며, 클러스터 내부의 클라이언트가 해당 서비스에 요청을 보내면 서비스는 해당하는 Endpoint 중 하나로 트래픽을 redirect 하게 된다.

 

  • 만약 Pod가 요청에 대한 세션을 가지고 있어야 한다면 sessionAffinity 를 사용할 수 있다. 이를 통해 요청은 계속해서 동일한 Pod로 전달된다.
  • Service는 TCP/UDP 트래픽을 분산하므로 HTTP 메시지를 볼 수 없다. ( 따라서 Cookie 값을 보고 로드밸런싱 한다던지의 기능을 수행할 수 없다. )
  • 여러개의 Port를 서비스에 연결할 수 있다.
  • targetPort로 숫자 이외의 http,https 등 alias 등을 사용할 수 있다. 이렇게 사용하면 Pod의 포트가 변경되어도 서비스를 수정할 필요가 없다.

Discovering Service

클러스터 내부에서 Service로 요청을 보내려면 해당 Service의 IP를 알아야 한다. 어떻게 알아야 할까?

  1. ENV
    1. 파드가 실행되면 환경변수 값들로 서비스의 IP와 포트가 들어간다. 가장 처음 존재하는 쿠버네티스 서비스의 경우
KUBERNETES_SERVICE_HOST= ... 
KUBERNETES_SERVICE_PORT= ...

로 파드 컨테이너의 환경변수로 들어간다.

 

  1. DNS
    1. 내부 DNS 서버인 kube-dns를 이용한다. 해당 DNS 서버에 서비스의 FQDN을 쿼리함으로써 서비스의 IP를 찾을 수 있다.

Service outside the cluster

Pod가 클러스터 외부 리소스에 접근할 때도 Service 리소스를 사용할 수 있다. externalName 타입의 서비스로 클러스터 외부의 도메인을 등록함으로써 서비스의 FQDN을 통해 클러스터 외부의 서비스에 접근할 수 있다.

 

Service를 클러스터 외부에 노출하기

 

클러스터 외부의 클라이언트가 Service에 요청을 보내기 위해서는 다양한 방식이 존재한다.

 

  1. NodePort
    1. 말 그대로 (워커)Node의 Port를 오픈한다. 해당 NodeIP:Port로 요청을 보내면 NodePort서비스는 Pod로 트래픽을 redirect 한다.
    2. 서비스에 dedicated한 Node의 Port를 할당한다. 해당 서비스로 트래픽을 보내려면 두가지 방법이 존재한다. 
    3. SERVICE_IP:PORT, nth NODE IP:NODEPORT
    4. SERVICE_IP의 경우 클러스터 내부 IP이고, 클러스터 외부에서는 NODE의 IP를 통해 접근할 수 있다.(물론 인바운드 NODEPORT에 대한 트래픽을 받아야 한다.)
    5. 이 방법의 경우 특정 노드가 죽어버리면 그 IP를 통해서는 더이상 트래픽을 받지 못한다는 단점이 있다.
  1. LoadBalancer
    1. Kubernetes Cloud Provider들이 제공해주는 LoadBalancer 리소스를 통해 dedicated IP로 트래픽을 받아 NodePort로 트래픽을 redirect한다.
    2. public하게 접근가능한 IP를 할당한다. 내부적으로는 NodePort서비스로 구현된다.
    3. LB의 IP:PORT로 접근 시 특정 NodePort로 연결한다. 해당 NodePort는 또 Pod로 트래픽을 분산한다.(implicitly assigned Nodeport)
  1. Ingress
  • 주로 HTTP 패킷을 받아 여러 서비스로 패킷을 전달한다. (다음 글에서 설명)

 

Peculiarities of External Connection

  1. 불필요한 Network hops
    1. 외부에서 Pod로 트래픽을 보내려면 LB -> NodePort -> Pod를 거친다. 여기서 Node에 Pod가 존재할 수도 있고 없으면 다른 Node로 보낼 수도 있는데, 이는 불필요한 hop수를 증가시킨다.
    2. Service 오브젝트의 스펙에 externalTrafficPolicy: local 을 명시하면 해당 Node에 존재하는 파드로만 트래픽을 분산한다. ( 이 경우 해당 Node에 실행중인 Pod가 없다면 hanging된다. 또한 트래픽을 불균등하게 받을 수 있다.. 특정 Node에 실행중인 Pod가 많으면)

 

  1. Client IP를 잃어버린다.
    1. Nodeport 서비스의 경우 SNAT해서 원래의 IP를 잃어버리고 Pod에 트래픽이 도달한다.

 

References

Service, Kubernetes up & running

[GCP] Cloud Run CI/CD 공부/CLOUD

Date 2021. 5. 24. 23:15

1. Cloud Run 이란 ?

Google 에서 제공하는 Serverless 솔루션이다.

AWS의 Lambda 와 유사하지만 Cloud Run은 Container 기반으로, Container 위에서 구동 가능한 것은 뭐든지 실행할 수 있다는 장점이 있다. AWS의 Lambda 에도 컨테이너를 실행할 수 있다.

크게 Managed Cloud Run과 ( 사용중 ) , GKE 위에서 돌아가는 Cloud Run for Anthos가 존재한다.

 

쿠버네티스 위에서 돌아가는 서버리스 솔루션인 Knative를 이용한다고 한다..!

 

어쨌든 사용에 중심을 두고 얘기하자면 다양한 장점이 존재한다.

1. 한번 서비스를 올리고 나면 관리할 포인트가 거의 제로에 가깝다. 알아서 다 해준다. 이런게 서버리스의 장점이다. 

2. 구글의 로깅 및 모니터링 서비스인 Stackdriver를 통해 컨테이너에서 나오는 로그(stdout 등)를 수집하고 관리할 수 있다.  

3. 버전관리가 쉽다. 배포전략을 여러가지로 가져갈 수 있다.(트래픽을 Cloud Run Revision마다 조절할 수 있다.)

4. 그리고 자동으로 HTTPS 엔드포인트도 제공해준다.

 

또한 서버리스 솔루션이지만 최소 인스턴스(컨테이너) 갯수를 남겨둘 수 있다. 이로 인해 Cold Start 문제에 대해 고민할 부분이 적어진다. ( 당연히 요금이 부과된다. )

2. Cloud Run CI/CD 구성

소스코드는 Github 으로 관리하고 있었고, 기존에는 Github Action을 이용해서 GCR(Google Container Registry)로 빌드하는 파이프라인으로 구성하려 했으나,


GCP 내에서도 Build 파이프라인을 구성해주는 Cloud Build란 솔루션이 있어 사용했다. Github Action의 경우 GCP 인증 관련 값들을 관리해줘야 했는데, Cloud Build는 당연히(?) 필요없다.

 

Cloud Build는 서버리스 CI/CD 관리 툴로, 도커 컨테이너에서 실행되는 빌드 단계들로 구성되어 있다.
여기엔 GCP 에서 제공하는 기본적인 이미지들 ( docker, gcloud.. )와 커스텀 빌드 이미지를 사용할 수 있다.

또한 빌드 트리거로 기본적인 Github Push 등 뿐만 아니라 Webhook, Cloud Pub/sub 메시지 등도 제공한다.

나는 간단하게 1. 소스코드 clone후 build 2. 빌드 이미지 GCR에 push 3. Cloud Run에 배포 4. Slack Webhook으로 빌드 알림 순으로 구성했다.  추후 방학때 시간이 되면 테스트도 구성해서 빌드 파이프라인에 포함시킬 예정이다.

Recent Posts

Popular posts

Recent Comments

Tag List

알고리즘 파이썬 TypeScript JWT IAC 컨테이너 GCP JavaScript 백준 인가 k8s DB DNS 네트워크 AWS ORM 테라폼 클라우드 API 운영체제 네임스페이스 도커 인증 리눅스
Total : Today : Yesterday :
Blog powered by Tistory, Designed by hanarotg