가동 시간 모니터링에는 웹 사이트, API 및 서버의 가용성 확인이 포함됩니다. 모니터는 사용 가능한지 여부를 판별하기 위해 지정된 간격 내에서 지정된 엔드포인트를 조사합니다. 목표는 시스템의 SLA에 지정된 대로 계약된 가용성 수준을 달성하고 계약이 충족되지 않을 때 차이를 확인하는 것입니다.
이 기사에서는 Prometheus blackbox_exporter를 기반으로 가동 시간 모니터링 시스템을 구축합니다. 사용자 지정 HTTP 모니터링 시스템을 구축하는 것은 간단할 수 있지만 내보내기 주변에 래퍼를 구축하면 다른 많은 프로브 기술에 액세스하고 시스템의 다른 요소를 빠르게 모니터링할 수 있습니다.
이 기사에서는 여러 기술의 사용을 다루며 가동 시간 시스템의 세부 사항에 대해 알아보기 전에 각 구성 요소에 대해 설명하겠습니다.
Google Compute Engine(GCE)이란 무엇입니까?
Compute Engine은 AWS의 EC2 컴퓨팅 오퍼링과 유사한 Google의 클라우드 컴퓨팅 서비스입니다. GCE는 안전하고 사용자 정의가 가능하여 소형 머신(최대 32개의 vCPU 및 128GB 메모리 지원)에서 표준 머신(최대 224개의 vCPU 및 896GB 메모리 지원) 및 집중적인 워크로드를 위한 기타 고급 머신에 이르기까지 다양한 워크로드에 적합합니다. 주문형 컴퓨터를 활용하여 시간당 필요에 맞게 확장합니다.
GCE는 컨테이너, 인스턴스 템플릿, 관리형 인스턴스 그룹을 포함하여 앱 배포를 위한 다양한 배포 메커니즘을 지원합니다. 이 기사의 목적을 위해 Ruby 가동 시간 모니터를 배포용 도커 컨테이너에 번들로 묶을 것입니다.
클라우드 스토리지란 무엇입니까?
Google Cloud Storage는 AWS의 S3 서비스와 유사한 고가용성 객체 스토리지 서비스입니다. Cloud Storage는 최신 앱의 여러 사용 사례를 가능하게 하는 많은 저장소 기능을 제공합니다. Ruby에서 Cloud Storage를 시작하려면 google-cloud-storage
를 사용합니다. gem을 사용하여 인증하고 Cloud Storage에서 파일을 업로드 및 다운로드:
require 'google/cloud/storage'
def upload_file bucket_name:, file_path:, file_name: nil
storage = Google::Cloud::Storage.new
bucket = storage.bucket bucket_name
file = bucket.create_file file_path, file_name
end
def download_file bucket_name: file_path, file_name: nil
storage = Google::Cloud::Storage.new
bucket = storage.bucket bucket_name
file = bucket.file file_name
file.download file_path
end
참고 :GOOGLE_APPLICATION_CREDENTIALS
를 설정해야 합니다. 환경에서 올바른 서비스 계정 키를 가리킵니다. 모든 Google 클라이언트 gem은 승인을 위해 이 환경 변수를 검색합니다. 그렇지 않으면 인증 관련 매개변수를 Google::Cloud::Storage.new
에 전달해야 합니다. . 그러나 앱이 GCE VM에서 실행 중인 경우 환경에 이미 설정되어 있습니다.
Cloud PubSub란 무엇입니까?
Cloud PubSub는 Google Cloud에서 제공하는 게시/구독 메시징 서비스입니다. 이 통신 형식은 AWS의 SNS와 유사한 비동기식 서비스 간 통신을 용이하게 하는 데 사용됩니다. 비동기식 통신으로 시스템을 구축하면 시스템의 성능, 확장성 및 안정성을 개선하는 데 도움이 될 수 있습니다. Ruby에서 Cloud PubSub를 시작하려면 google-cloud-pubsub
를 사용합니다. 이벤트를 인증, 게시 및 수신하는 gem:
require 'google/cloud/pubsub'
def publish_message topic_id:, message: nil
pubsub = Google::Cloud::Pubsub.new
topic = pubsub.topic topic_id
topic.publish_async message do |result|
raise "Failed to publish message" unless result.succeeded?
puts "Message published asynchronously"
end
topic.async_publisher.stop.wait!
rescue StandardError => e
puts "Received error while publishing: #{e.message}"
end
def receive_message subscription_id: nil, wait_time: 200.seconds
pubsub = Google::Cloud::Pubsub.new
subscription = pubsub.subscription subscription_id
subscriber = subscription.listen do |received_message|
puts "Received message: #{received_message.data}"
received_message.acknowledge!
end
subscriber.start
sleep wait_time
end
참고 :Cloud Storage에 대해 설명된 인증도 여기에 적용됩니다.
Cloud Storage와 PubSub를 활용하면 매우 흥미로운 솔루션을 구축할 수 있습니다. 종종 우리는 객체를 업로드하고 업데이트를 추적하기를 원합니다. 이는 수명 주기입니다. 특정 이벤트를 기반으로 생성, 업데이트, 삭제 및 특정 작업을 수행합니다. 이것이 여전히 추상적이라면 두 가지 사용 사례를 살펴보겠습니다.
- 이미지 서비스:이미지 서비스 구축. 이미지 및 비디오 스토리지를 제공하고 이러한 데이터에 대한 변환을 수행하는 Cloudinary와 유사한 것을 만들고 싶다고 가정해 보겠습니다. Cloud Storage는 데이터를 저장하고 버전을 지정하는 데 도움이 될 수 있지만 PubSub를 사용하면 고객이 사전 처리된 버전을 요청하기 전에도 버킷에서 이벤트를 수신하고 데이터에 대해 특정 유형의 사전 처리를 수행할 수 있습니다.
- 구성 파일 배포. 인프라 엔지니어링의 일반적인 문제는 여러 서버에 구성을 롤아웃하고 손쉬운 롤백을 제공하는 것입니다. 서버 구성을 담당하는 중앙 서버가 있고 구성을 한 번 업데이트하고 구성을 서버 집합에 배포하고 싶다고 상상해 보십시오. Cloud Storage 및 Cloud PubSub를 사용하여 PubSub를 통해 수신 대기하는 서버에 에이전트를 구축하여 객체 알림을 받고 이러한 이벤트를 기반으로 조치를 취할 수 있습니다. 또한 잘못된 변경(잘못된 구성 변경은 다운타임 😩의 일반적인 원인임)인 경우 객체 버전 관리를 통해 롤백을 수행할 수 있습니다.
이 기사에서는 위에서 설명한 두 번째 사용 사례를 사용하여 Blackbox Exporter용 Ruby 래퍼를 빌드합니다. 래퍼는 한 프로세스에서 내보내기를 실행하고 다른 프로세스를 실행하여 GCP의 버킷에서 구성 변경 사항을 관찰한 다음 내보내기를 실시간으로 다시 로드합니다. 준비 되었나요? 신나게 놀자!
블랙박스 내보내기란 무엇입니까?
Blackbox Exporter는 HTTP, HTTPS, DNS, TCP 및 ICMP를 통해 엔드포인트를 조사하기 위해 Prometheus 팀에서 구축한 오픈 소스 도구입니다. 내보내기는 Grafana 및 Prometheus 배포와 함께 배포되어야 합니다. 전체 설정은 다음과 같습니다.
Blackbox 래퍼는 구성된 모든 엔드포인트를 조사하고 Prometheus는 다른 대상과 마찬가지로 내보내기를 스크랩합니다. 그런 다음 Grafana는 그래프로 표시할 데이터를 Prometheus에서 검색합니다. blackbox_exporter --config.file blackbox.yml
과 같은 내보내기 바이너리를 실행합니다. . Blackbox Exporter를 사용하면 바이너리를 종료하고 다시 시작하지 않고도 새로운 구성으로 내보내기를 실시간으로 다시 로드할 수 있습니다. 이것은 초 단위로 측정된 간격으로 끝점을 스크래핑할 때 매우 유용할 수 있습니다.
BlackboxWrapper 서비스 사양
코드를 자세히 살펴보기 전에 서비스 사양을 강조해 보겠습니다.
BlackboxWrapper
서비스는 두 개의 프로세스를 실행합니다.- 첫 번째 프로세스는
blackbox_exporter
를 실행합니다. 바이너리. - 두 번째 프로세스는 GCP의 버킷 변경 사항을 수신 대기하고 첫 번째 프로세스를 다시 시작합니다.
- 첫 번째 프로세스는
- 서비스는 도커 이미지로 배포되어
blackbox_exporter
와 함께 서비스를 패키징할 수 있습니다. 바이너리.
건설을 시작합시다
먼저 앱 디렉터리를 만든 다음 디렉터리를 입력합니다.
mkdir blackbox-wrapper && cd blackbox-wrapper
표준 Ruby 애플리케이션과 마찬가지로 bundler
를 사용합니다. 래퍼의 종속성을 관리합니다. Gemfile 생성:
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
ruby '2.7.2'
gem 'google-cloud-storage'
gem 'google-cloud-pubsub'
gem 'rake'
gem 'pry'
그런 다음 bundle install
를 실행합니다. .
이제 코드를 저장할 파일을 만듭니다. app.rb
.
이 파일은 우리 서비스의 진입점 역할을 합니다. 컨테이너에 앱을 배포할 것이므로 이 파일은 CMD
에 지정됩니다. Dockerfile
의 명령 나중에.
touch app.rb
도커파일 생성
일부 항목은 이 파일에서 의도적으로 생략되었습니다. 아래 코드는 이 문서에 필요한 중요한 구성 요소를 강조 표시합니다.
FROM ruby:2.7.2
RUN mkdir /app
WORKDIR /app
COPY . .
# Install other dependencies
...
# Download & Install blackbox exporter
RUN curl -SL \
https://github.com/prometheus/blackbox_exporter/releases/download/v0.18.0/blackbox_exporter-0.18.0.linux-386.tar.gz | \
tar xvz -C /tmp && \
mv /tmp/blackbox_exporter-0.18.0.linux-386/blackbox_exporter /usr/local/bin && \
mkdir /etc/blackbox && \
mv /tmp/blackbox_exporter-0.18.0.linux-386/blackbox.yml /etc/blackbox/
# Specify entry point.
CMD ["bundle", "exec", "ruby", "app.rb" ]
위의 내용에서 다음 사항에 유의해야 합니다.
- 우리는 Ruby 이미지를 사용했습니다. -
ruby:2.7.2
- Ruby가 설치된 기본 이미지로. blackbox_exporter
를 설치했습니다. 바이너리를 만들고PATH
에서 액세스할 수 있는 디렉토리로 이동했습니다. .app.rb
를 실행할 컨테이너의 진입점을 지정했습니다. 컨테이너 시작 시.
래퍼 서비스 구축
이것은 모든 것을 하나로 묶는 Ruby 서비스입니다. main.rb
에서 , 다음을 배치하십시오:
require 'rubygems'
require 'bundler/setup'
require "google/cloud/pubsub"
require "google/cloud/storage"
CONFIG_BUCKET = ENV['BUCKET_NAME']
TOPIC = ENV['PUBSUB_TOPIC']
TOPIC_SUBSCRIPTION = ENV['TOPIC_SUBSCRIPTION']
class ProcessNotification
def initialize(file, attr, blackbox_exporter)
@file = file
@attr = attr
@blackbox_exporter = blackbox_exporter
end
def call
return if @attr['eventType'] == 'OBJECT_DELETE'
@blackbox_exporter.write @file
@blackbox_exporter.reload
end
end
class BlackBoxExporter
CONFIG_FILE = '/etc/blackbox/blackbox.yml'
def initialize
@blackbox_pid = nil
end
def start
return unless @blackbox_pid.nil?
@blackbox_pid = fork do
exec('blackbox_exporter', '--config.file', CONFIG_FILE)
end
end
def write(file)
file.download CONFIG_FILE
end
def reload
# Send SIGHUP signal
Process.kill('HUP', @blackbox_pid)
end
def shutdown
Process.kill('KILL', @blackbox_pid)
end
end
class Subscriber
class NotificationConfigError < StandardError
end
SUPPORTED_FILE_TYPES = ['blackbox.yml']
def initialize(blackbox_exporter)
@pubsub = Google::Cloud::Pubsub.new
@storage = Google::Cloud::Storage.new
@subscription_name = ENV['TOPIC_SUBSCRIPTION'] # Retrieve a subscription
@bucket = @storage.bucket CONFIG_BUCKET
@subscription = @pubsub.subscription @subscription_name
@blackbox_exporter = blackbox_exporter
end
def listen
create_notification_config
puts "Starting subscriber"
@subscriber = @subscription.listen do |received_message|
process_notification(received_message)
end
@subscriber.on_error do |exception|
process_exception(exception)
end
@subscriber.start
end
def process_notification(received_message)
data = received_message.message.data
published_at = received_message.message.published_at
attributes = received_message.message.attributes
puts "Data: #{data}, published at #{published_at}, Attr: #{attributes}"
received_message.acknowledge!
parsed_data = JSON.parse(data)
file_name = parsed_data['name']
return unless SUPPORTED_FILE_TYPES.include?(file_name)
file = @bucket.file file_name
process_notification = ProcessNotification.new(file, attributes, @blackbox_exporter)
process_notification.call
end
def process_exception(exception)
puts "Exception: #{exception.class} #{exception.message}"
end
def shutdown
@subscriber.stop!(10)
end
def create_notification_config
topic = @pubsub.topic TOPIC
notification_exists = @bucket.notifications.count == 1
unless notification_exists
@bucket.notifications.each do |notification|
notification.delete
end
end
@bucket.create_notification topic.name
rescue StandardError => e
raise NotificationConfigError, e.message
end
end
class BlackboxWrapper
def initialize
@blackbox_exporter = BlackBoxExporter.new
@subscriber = Subscriber.new(@blackbox_exporter)
end
def start
@blackbox_exporter.start
@subscriber.listen
at_exit do
@blackbox_exporter.shutdown
@subscriber.shutdown
end
# Block, letting processing threads continue in the background
sleep
end
end
blackbox_wrapper = BlackboxWrapper.new
blackbox_wrapper.start
위의 코딩은 많은 양이지만 아래부터 시작해 보겠습니다.
BlackboxWrapper
:이 클래스는 우리 서비스의 진입점입니다. -.start
메서드는 다음을 수행합니다.blackbox_exporter
시작 다른 프로세스의 바이너리를 사용하여 엔드포인트 검색을 시작합니다.subscriber
시작 다른 프로세스에서 버킷 변경 사항을 수신합니다.- 그런 다음
sleep
를 호출합니다. 앱이 무한정 실행되도록 메인 프로세스에서.
BlackboxExporter
는 어떻게 일?.start
메소드는exec
를 사용합니다.blackbox_exporter
를 실행하는 커널 메서드 다른 프로세스의 바이너리입니다..reload
메소드는SIGHUP
를 보냅니다.blackbox_exporter
를 다시 로드하라는 신호 새 구성으로 바이너리.ProcessNotification
에서 언급했듯이 클래스에서 내보내기가 다시 로드되기 전에 새 구성 파일이 구성 파일 위치에 기록됩니다.
Subscriber
는 일?.listen
메소드는NotificationConfiguation
생성으로 시작합니다. .NotificationConfiguration
다음 세 가지를 지정하는 규칙입니다.- 알림을 받을 게시/구독의 주제
- 알림을 전송하는 이벤트입니다. 알림을 트리거할 수 있는 다양한 이벤트 유형을 보려면 여기를 클릭하십시오.
- 알림에 포함된 정보입니다.
#create_notification_config
메서드는 또한NotificationConfiguration
이 하나만 있는지 확인합니다.; 그렇지 않으면 모든 것을 삭제하고 하나를 만듭니다. 이렇게 하면 알림이 한 번만 전송됩니다..listen
메서드는@subscription.listen
도 호출합니다. 구독 중인 버킷의 알림 변경 사항 수신을 시작합니다. 이것은 설명된 대로 다른 프로세스에서 무한히 실행됩니다.#process_notification
전송된 모든 알림 업데이트에 대해 메서드가 호출됩니다.SUPPORTED_FILE_TYPES
가 있습니다. , 관심 있는 버킷의 파일을 식별하는 데 사용하고 나머지는 수행하지 않습니다.
ProcessNotification
:알림 처리, 업데이트된 구성 다운로드, 파일에 쓰기,blackbox_exporter
다시 로드를 담당합니다. 바이너리.
로컬에서 서비스 실행
서비스를 로컬에서 실행하고 테스트하려면 앱 디렉터리의 루트에서 다음을 실행하세요.
export BUCKET_NAME='{insert-bucket-name}'
export PUBSUB_TOPIC='{insert-pubsub-topic}'
export TOPIC_SUBSCRIPTION='{insert-subscription-name}'
export GOOGLE_APPLICATION_CREDENTIALS='{insert-path-to-service-key-json}'
bundle exec ruby app.rb
Google Compute Engine에 서비스 배포
클라우드의 여러 측면과 마찬가지로 동일한 결과를 얻을 수 있는 방법은 여러 가지가 있지만 현대 소프트웨어 엔지니어링에서는 몇 가지 타당한 이유로 CI/CD 프로세스를 권장합니다. 따라서 setup-gcloud를 사용하여 Github Actions에서 서비스를 배포하는 데 집중할 것입니다.
배포 파일(.github/workflows/deploy.yml)을 설정해 보겠습니다.
name: Build and Deploy to Google Compute Engine
on:
push:
branches:
- main
env:
PROJECT_ID: ${{ secrets.GCE_PROJECT }}
GCE_INSTANCE: ${{ secrets.GCE_INSTANCE }}
GCE_INSTANCE_ZONE: us-central1-a
BUCKET_NAME: demo-configurations
PUBSUB_TOPIC: demo-configurations-bucket-notifications
TOPIC_SUBSCRIPTION: demo-bucket-changes-subscription
jobs:
setup-build-publish-deploy:
name: Setup, Build, Publish, and Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
# Setup gcloud CLI
- uses: google-github-actions/setup-gcloud@master
with:
version: '290.0.1'
service_account_key: ${{ secrets.GCE_SA_KEY }}
project_id: ${{ secrets.GCE_PROJECT }}
# Configure Docker to use the gcloud command-line tool as a credential
# helper for authentication
- run: |-
gcloud --quiet auth configure-docker
# Build the Docker image
- name: Build
run: |-
docker build --tag "gcr.io/$PROJECT_ID/$GCE_INSTANCE-image:$GITHUB_SHA" .
# Push the Docker image to Google Container Registry
- name: Publish
run: |-
docker push "gcr.io/$PROJECT_ID/$GCE_INSTANCE-image:$GITHUB_SHA"
- name: Deploy
run: |-
gcloud compute instances update-container "$GCE_INSTANCE" \
--zone "$GCE_INSTANCE_ZONE" \
--container-image "gcr.io/$PROJECT_ID/$GCE_INSTANCE-image:$GITHUB_SHA" \
--container-env "BUCKET_NAME=$BUCKET_NAME,PUBSUB_TOPIC=$PUBSUB_TOPIC,TOPIC_SUBSCRIPTION=$TOPIC_SUBSCRIPTION"
--container-env
플래그는 배포 단계에서 설정되어 필요한 환경 변수를 Github Actions secret에서 안전한 방식으로 컨테이너로 전달합니다.
비밀 및 환경 변수
다음으로 github 작업에 대한 비밀을 설정합니다.
--container-env
를 사용하여 컨테이너에 대한 환경 변수를 설정합니다. 깃발. Github 작업에서 설정하기 때문에 민감한 데이터에는 secrets를 사용하고 민감하지 않은 데이터에는 env 변수를 사용할 수 있습니다.
GCP 리소스 만들기
GCP 콘솔에서 버킷을 생성해 보겠습니다.
또한 GCP 콘솔에서 PubSub 주제를 만들 것입니다.
클라우드 스토리지 버킷의 서비스 에이전트 설정 - IAM 역할 - pubsub.publisher
콘솔에서. 각 프로젝트에는 PubSub 알림과 같은 일부 백그라운드 작업을 담당하는 연결된 Cloud Storage 서비스 계정이 있습니다. 찾는 방법을 알아보려면 여기를 클릭하십시오.
마지막으로 GCP 콘솔에서 구독을 만듭니다.
짜잔! 🎉 클라우드 기능이 성공적으로 배포되었습니다.
결론
여기까지 했다면 쿠키를 받을 자격이 있습니다 🍪 . 이것이 여러 최적화를 달성할 수 있는 잠재적으로 훌륭한 솔루션의 첫 번째 버전이라고 생각합니다. 예를 들어 다음을 달성할 수 있습니다.
- blackbox_exporter를 서버리스 기능으로 배포하여 업타임 모니터링에 이상적인 여러 지역을 지원하고 Cloud Storage에서 버킷 구성 업데이트를 담당하는 마스터 서버를 배포합니다.
- 잠재적으로 이전 시점에서 우리는 이것을 인기 있는 클라우드 제공업체에 통합하여 동일한 기능을 달성하는 앱으로 추상화할 수 있으므로 클라우드 불가지론자로 만들 수 있습니다. 추신:인기 있는 클라우드 제공업체(GCP, AWS, Azure)는 서비스 전반에 걸쳐 동일한 기능을 제공합니다.
-
다음 기사에서는 이 솔루션을 기반으로 클라우드 저장소 개체 버전 관리를 통해 롤백을 제공하여 잘못된 업데이트로 구성 업데이트를 복구할 수 있도록 할 것입니다.
-
Docker로 배포하면 단순히 패키징 문제를 해결할 수 있지만 이미 알고 있듯이 서비스를 패키징하는 다양한 방법이 있습니다. 이 문서에서는 간단하게 하기 위해 Docker를 선택했습니다.
용어집
- 프로메테우스 오픈 소스 시스템 모니터링 및 경고 툴킷입니다. 여기에는 시계열 데이터를 스크랩하고 저장하는 서버, 애플리케이션 코드를 계측하기 위한 클라이언트 라이브러리, 경고를 처리하는 경고 관리자가 포함됩니다.
- 그라파나 저장 위치에 관계없이 측정항목을 쿼리, 시각화, 경고 및 이해할 수 있는 시각화 시스템입니다.
- 블랙박스 내보내기 Prometheus 팀이 HTTP, HTTPS, DNS, TCP 및 ICMP를 통해 엔드포인트를 조사하기 위해 구축한 오픈 소스 도구입니다.