영구 디스크 스냅샷을 사용하여 콜드 복구 가능한 웹 서버 배포

Last reviewed 2021-08-04 UTC

이 문서에서는 관리형 인스턴스 그룹영구 디스크 스냅샷을 사용하여 웹 서버에 콜드 장애 조치 토폴로지를 배포하는 방법을 설명합니다. 이 문서는 운영팀 및 관리팀에 근무하는 설계자와 사용자를 대상으로 합니다.

데이터를 저장하는 영구 디스크가 있는 단일 VM을 실행하는 관리형 인스턴스 그룹을 만듭니다. 예약된 영구 디스크 스냅샷을 사용하면 장애 조치 시나리오에서 데이터 손실이 최소화됩니다. 다음 다이어그램과 같이 외부 애플리케이션 부하 분산기에서 사용자를 관리형 인스턴스 그룹에서 실행되는 VM으로 안내합니다.

외부 애플리케이션 부하 분산기에서 사용자를 관리형 인스턴스 그룹에서 실행되는 단일 VM으로 안내하고, 리소스 정책은 VM에 연결된 영구 디스크의 스냅샷을 정기적으로 생성합니다.

인스턴스 장애가 발생하면 관리형 인스턴스 그룹이 동일한 영역에서 VM을 다시 만들려고 시도합니다. 장애가 영역 수준에서 발생한 경우 Cloud Monitoring 또는 유사 서비스에서 문제가 발생한 것을 확인하고, 다른 영역 또는 리전에서 또 다른 관리형 인스턴스 그룹을 수동으로 만들 수 있습니다. 장애 조치 시나리오에서 플랫폼은 최신 영구 디스크 스냅샷을 사용하여 대체 디스크를 만들고 인스턴스 그룹의 새 VM에 이를 연결합니다.

이 문서에서는 VM 또는 부하 분산기의 외부 IP 주소를 사용하여 웹 서버의 기본 페이지를 확인합니다. 이 접근 방식을 사용하면 등록된 도메인 이름이 없는 경우 DNS 변경 없이 콜드 장애 조치 패턴을 테스트할 수 있습니다. 프로덕션 환경에서는 부하 분산기에 할당된 외부 IP 주소로 확인되는 Cloud DNS 영역 및 레코드를 만들고 구성하세요.

이 패턴은 특정 수준의 데이터 보호를 유지하면서 여러 VM 또는 리전 영구 디스크를 실행하는 비용 차이의 균형을 맞춥니다. 하나의 VM 및 영구 디스크를 실행하기 때문에 비용이 낮아지기는 하지만, 영구 디스크 스냅샷은 설정된 간격으로만 확보되므로 데이터가 손실될 위험이 있습니다. 데이터 손실 가능성을 줄이려면 리전 영구 디스크를 사용하는 콜드 복구 가능한 웹 서버를 배포하는 것이 좋습니다.

다음 표에서는 리전 영구 디스크 또는 영구 디스크 스냅샷을 사용하는 콜드 복구 방법에 관한 데이터 보호 옵션의 개략적인 차이를 간략히 설명합니다. 자세한 내용은 영구 디스크를 사용하는 고가용성 옵션을 참조하세요.

리전 영구 디스크 영구 디스크 스냅샷
데이터 손실 - 복구 지점 목표(RPO) 한 영역의 지속적인 중단 또는 네트워크 연결 해제와 같은 단일 오류 제로화 일반적으로 1시간 이상인 마지막 스냅샷 수행 이후의 데이터입니다.

잠재적 데이터 손실은 스냅샷 생성 빈도를 제어하는 스냅샷 일정에 따라 다릅니다.
복구 시간 목표(RTO) 새 VM의 배포 시간 및 리전 영구 디스크를 다시 연결하기 위한 추가 시간(초) 새 VM 인스턴스의 배포 시간 및 최신 스냅샷에서 새 영구 디스크를 만들기 위한 추가 시간입니다.

디스크 만들기 시간은 스냅샷 크기에 따라 달라지며, 몇 십 분 또는 몇 시간까지 걸릴 수 있습니다.
비용 리전 영구 디스크가 다른 영역으로 지속적으로 복제될 때 스토리지 비용이 배가됩니다. 사용한 스냅샷 공간에 대해서만 비용을 지불합니다.
자세한 내용은 디스크 및 이미지 가격 책정을 참조하세요.

목표

  • 영구 디스크가 있는 VM을 실행하는 관리형 인스턴스 그룹을 만듭니다.
  • 영구 디스크 스냅샷을 정기적으로 생성하도록 스냅샷 일정을 구성합니다.
  • 인스턴스 템플릿 및 시작 스크립트를 만듭니다.
  • 외부 애플리케이션 부하 분산기를 만들고 구성합니다.
  • 대체 관리형 인스턴스 그룹으로 콜드 웹 서버 장애 조치를 테스트합니다.

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  3. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  4. Compute Engine API 사용 설정

    API 사용 설정

  5. Google Cloud CLI를 설치합니다.
  6. gcloud CLI를 초기화하려면 다음 명령어를 실행합니다.

    gcloud init
  7. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  8. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  9. Compute Engine API 사용 설정

    API 사용 설정

  10. Google Cloud CLI를 설치합니다.
  11. gcloud CLI를 초기화하려면 다음 명령어를 실행합니다.

    gcloud init
  12. Google Cloud CLI를 설치하지 않고도 Google Cloud 콘솔에서 Google Cloud CLI를 실행할 수 있습니다. Google Cloud 콘솔에서 gcloud CLI를 실행하려면 Cloud Shell을 사용하세요.

환경 준비

이 섹션에서는 리소스 이름과 위치에 대한 몇 가지 변수를 정의합니다. 이러한 변수는 리소스를 배포할 때 Google Cloud CLI 명령어에서 사용됩니다.

이 문서에서 달리 명시하지 않는 한, 모든 명령어를 Cloud Shell 또는 로컬 개발 환경에 입력합니다.

  1. 여기서 PROJECT_ID는 프로젝트 ID로 바꿉니다. 필요한 경우 app과 같은 리소스의 고유 이름 서픽스를 제공합니다.

    us-central1과 같은 리전과 us-central1-aus-central1-f와 같은 해당 리전 내의 두 영역을 지정합니다. 이러한 영역으로 초기 영구 디스크 및 관리형 인스턴스 그룹이 배포되는 위치와 필요한 경우 수동으로 장애 조치할 수 있는 위치를 정의합니다.

    PROJECT_ID=PROJECT_ID
    NAME_SUFFIX=app
    REGION=us-central1
    ZONE1=us-central1-a
    ZONE2=us-central1-f
    

VPC 및 서브넷 만들기

VM에 대한 네트워크 액세스 권한을 제공하려면 Virtual Private Cloud(VPC) 및 서브넷을 만듭니다. 관리형 인스턴스 그룹이 단일 리전 내의 영역 간에만 작동하므로 서브넷 하나만 생성됩니다. 환경에서 사용 중인 IP 주소 범위를 관리하기 위한 커스텀 서브넷 모드의 이점에 대한 자세한 내용은 커스텀 모드 VPC 네트워크 사용을 참조하세요.

  1. 커스텀 서브넷 모드로 VPC를 만듭니다.

    gcloud compute networks create network-$NAME_SUFFIX \
        --subnet-mode=custom
    

    Cloud Shell 프롬프트가 표시되면 이 첫 번째 요청을 승인하여 API를 호출합니다.

  2. 새 VPC에서 서브넷을 만듭니다. 네트워크 범위에 맞는 고유한 주소 범위(예: 10.1.0.0/20)를 정의합니다.

    gcloud compute networks subnets create subnet-$NAME_SUFFIX-$REGION \
        --network=network-$NAME_SUFFIX \
        --range=10.1.0.0/20 \
        --region=$REGION
    

방화벽 규칙 만들기

  1. 부하 분산기 및 관리형 인스턴스 그룹의 웹 트래픽 및 상태 확인을 허용하는 방화벽 규칙을 만듭니다.

    gcloud compute firewall-rules create allow-http-$NAME_SUFFIX \
        --network=network-$NAME_SUFFIX \
        --direction=INGRESS \
        --priority=1000 \
        --action=ALLOW \
        --rules=tcp:80 \
        --source-ranges=0.0.0.0/0 \
        --target-tags=http-server
    
    gcloud compute firewall-rules create allow-health-check-$NAME_SUFFIX \
        --network=network-$NAME_SUFFIX \
        --action=allow \
        --direction=ingress \
        --source-ranges=130.211.0.0/22,35.191.0.0/16 \
        --target-tags=allow-health-check \
        --rules=tcp:80
    

    HTTP 규칙은 http-server 태그가 적용되는 모든 VM에 대한 트래픽과 0.0.0.0/0 범위를 사용하는 모든 소스로부터의 트래픽을 허용합니다. 상태 확인 규칙의 경우 Google Cloud의 기본 범위는 플랫폼이 리소스 상태를 올바르게 확인할 수 있도록 설정됩니다.

  2. 기본 VM 이미지의 초기 구성에 대해 SSH 트래픽을 허용하려면 --source-range 매개변수를 사용하여 해당 환경에 대한 방화벽 규칙 범위를 지정합니다. 조직에 사용되는 소스 범위를 결정하려면 네트워크 팀과 협력이 필요할 수 있습니다.

    IP_ADDRESS_SCOPE를 고유 IP 주소 범위로 바꿉니다.

    gcloud compute firewall-rules create allow-ssh-$NAME_SUFFIX \
        --network=network-$NAME_SUFFIX \
        --direction=INGRESS \
        --priority=1000 \
        --action=ALLOW \
        --rules=tcp:22 \
        --source-ranges=IP_ADDRESS_SCOPE
    
  3. 방화벽 규칙을 만든 후 다음 세 가지 규칙이 추가되었는지 확인합니다.

    gcloud compute firewall-rules list \
        --project=$PROJECT_ID \
        --filter="NETWORK=network-$NAME_SUFFIX"
    

    다음 예시 출력은 3개 규칙이 올바르게 생성된 것을 보여줍니다.

    NAME                    NETWORK      DIRECTION  PRIORITY  ALLOW
    allow-health-check-app  network-app  INGRESS    1000      tcp:80
    allow-http-app          network-app  INGRESS    1000      tcp:80
    allow-ssh-app           network-app  INGRESS    1000      tcp:22
    

기본 VM 이미지 만들기 및 구성

추가 구성 없이 배포하는 VM을 만들려면 커스텀 VM 이미지를 사용합니다. 이 이미지는 OS 및 Apache 구성을 캡처하며 다음 단계에서 관리형 인스턴스 그룹에 각 VM을 만드는 데 사용됩니다.

영구 디스크를 사용하여 애플리케이션 데이터를 저장합니다. 이 문서에서는 기본 Apache 웹사이트를 사용하여 애플리케이션을 제공합니다. 이 문서의 뒷부분에서 영구 디스크에 연결된 스냅샷 일정을 만들어 자동 디스크 스냅샷을 만듭니다.

VM에서 영구 디스크에 기본 index.html 파일을 만들고 /var/www/example.com에 마운트합니다. /etc/apache2/sites-available/example.com.conf의 Apache 구성 파일은 마운트된 영구 디스크 위치로부터 웹 콘텐츠를 제공합니다.

다음 다이어그램은 영구 디스크에 저장된 Apache에서 제공하는 기본 HTML 페이지를 보여줍니다.

VM에는 마운트된 디스크 위치에서 로드할 Apache 구성 파일이 있는 영구 디스크에 저장된 기본 HTML 페이지가 포함됩니다.

다음 단계에서 이 환경을 빌드합니다.

  1. 10GiB SSD를 만듭니다. 스토리지 요구사항과 소비된 공간이 아닌 프로비저닝된 공간에 대한 비용 지불과 관련된 요금을 이해할 수 있습니다. 자세한 내용은 영구 디스크 가격 책정을 참조하세요.

    gcloud compute disks create disk-$NAME_SUFFIX \
        --zone $ZONE1 \
        --size=10 \
        --type=pd-ssd
    
  2. 연결된 영구 디스크가 있는 기본 VM을 만듭니다.

    gcloud compute instances create vm-base-$NAME_SUFFIX \
        --zone=$ZONE1 \
        --machine-type=n1-standard-1 \
        --subnet=subnet-$NAME_SUFFIX-$REGION \
        --tags=http-server \
        --image=debian-10-buster-v20210721 \
        --image-project=debian-cloud \
        --boot-disk-size=10GB \
        --boot-disk-type=pd-balanced \
        --boot-disk-device-name=vm-base-$NAME_SUFFIX \
        --disk=mode=rw,name=disk-$NAME_SUFFIX,device-name=disk-$NAME_SUFFIX
    

    이 문서의 시작 부분에 정의된 매개변수를 사용하여 VM의 이름을 지정하고 올바른 서브넷에 연결합니다. 또한 부팅 디스크 및 데이터 디스크에 대한 매개변수로부터 이름을 할당합니다.

  3. 간단한 웹사이트를 설치하고 구성하려면 먼저 SSH를 사용하여 기본 VM에 연결합니다.

    gcloud compute ssh vm-base-$NAME_SUFFIX --zone=$ZONE1
    
  4. VM에 대한 SSH 세션에서 원하는 편집기로 VM을 구성하는 스크립트를 만듭니다. 다음 예시에서는 Nano를 편집기로 사용합니다.

    nano configure-vm.sh
    

    다음 구성 스크립트를 파일에 붙여넣습니다. NAME_SUFFIX를 이 문서의 시작 부분에서 설정한 값과 일치하도록 업데이트합니다(예: app).

    #!/bin/bash
    
    NAME_SUFFIX=app
    
    # Create directory for the basic website files
    sudo mkdir -p /var/www/example.com
    sudo chmod a+w /var/www/example.com
    sudo chown -R www-data: /var/www/example.com
    
    # Find the disk name, then format and mount it
    DISK_NAME="google-disk-$NAME_SUFFIX"
    DISK_PATH="$(find /dev/disk/by-id -name "${DISK_NAME}" | xargs -I '{}' readlink -f '{}')"
    
    sudo mkfs.ext4 -m 0 -E lazy_itable_init=0,lazy_journal_init=0,discard $DISK_PATH
    sudo mount -o discard,defaults $DISK_PATH /var/www/example.com
    
    # Install Apache, additional utilities, and cloud-init
    sudo apt-get update && sudo apt-get -y install apache2 moreutils cloud-init
    
    # Write out a basic HTML file to the mounted persistent disk
    sudo tee -a /var/www/example.com/index.html >/dev/null <<'EOF'
    <!doctype html>
    <html lang=en>
    <head>
    <meta charset=utf-8>
        <title>HA / DR example</title>
    </head>
    <body>
        <p>Welcome to a test web server with persistent disk snapshots!</p>
    </body>
    </html>
    EOF
    
    # Write out an Apache configuration file
    sudo tee -a /etc/apache2/sites-available/example.com.conf >/dev/null <<'EOF'
    <VirtualHost *:80>
            ServerName www.example.com
    
            ServerAdmin webmaster@localhost
            DocumentRoot /var/www/example.com
    
            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
    EOF
    
    # Enable the Apache configuration file and reload service
    sudo a2dissite 000-default
    sudo a2ensite example.com.conf
    sudo systemctl reload apache2
    
  5. 파일을 작성하고 편집기를 종료합니다. 예를 들어 Nano에서 Ctrl-O를 사용하여 파일을 작성하고 Ctrl-X로 종료합니다.

  6. 구성 스크립트를 실행 가능하게 만든 다음 실행합니다.

    chmod +x configure-vm.sh
    ./configure-vm.sh
    
  7. 인스턴스 장애가 발생하여 관리형 인스턴스 그룹이 이 기본 VM으로부터 대체 인스턴스를 만들어야 하는 경우 애플리케이션 데이터를 사용할 수 있어야 합니다. 새 VM 각각에서 다음 단계가 자동으로 실행됩니다.

    • 메타데이터 서버에서 일부 정보 가져오기
    • 영구 디스크의 최신 스냅샷 가져오기
    • 이 최신 스냅샷에서 디스크 만들기
    • VM에 새 디스크 연결
    • VM 내에서 디스크 마운트

    VM에 필요한 단계를 진행하는 app-startup.sh라는 시작 스크립트를 만듭니다. 이 시작 스크립트는 다음 단계의 인스턴스 템플릿에 적용됩니다.

    sudo mkdir /opt/cloud-init-scripts
    
    sudo tee -a /opt/cloud-init-scripts/app-startup.sh >/dev/null <<'EOF'
    #!/bin/bash
    
    # Install jq and get an access token for API requests
    apt-get install -y jq
    OAUTH_TOKEN=$(curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" \
        -H "Metadata-Flavor: Google" --silent | jq -r '.access_token')
    
    # Make a request against the metadata server to determine the project name,
    # instance name, and what zone it's running in
    ZONE_INFO=$(curl http://metadata.google.internal/computeMetadata/v1/instance/zone \
        -H "Metadata-Flavor: Google" --silent)
    PROJECT_NAME=$(curl http://metadata.google.internal/computeMetadata/v1/instance/zone \
        -H "Metadata-Flavor: Google" --silent | awk -v FS="/" '{print $2}')
    ZONE_NAME=$(curl http://metadata.google.internal/computeMetadata/v1/instance/zone \
        -H "Metadata-Flavor: Google" --silent | sed 's:.*/::')
    INSTANCE_NAME=$(curl http://metadata.google.internal/computeMetadata/v1/instance/name \
        -H "Metadata-Flavor: Google" --silent)
    
    # Get the latest snapshot of the app disk
    LATEST_SNAPSHOT=$(curl -X GET -H "Authorization: Bearer $OAUTH_TOKEN" \
        https://compute.googleapis.com/compute/v1/projects/$PROJECT_NAME/global/snapshots \
        --silent | jq -s '.[].items[] | select(.name | contains("disk-$NAME")) | .name' \
        | sort -r | head -n 1 | tr -d '"')
    
    # Create a persistent disk using the latest persistent disk snapshot
    curl -X POST -H "Authorization: Bearer $OAUTH_TOKEN" -H "Content-Type: application/json; charset=utf-8" \
        https://compute.googleapis.com/compute/v1/$ZONE_INFO/disks \
        --data '{"name":"'$LATEST_SNAPSHOT'-restored","sizeGb":"10","type":"zones/'$ZONE_NAME'/diskTypes/pd-ssd","sourceSnapshot":"https://www.googleapis.com/compute/v1/projects/'$PROJECT_NAME'/global/snapshots/'$LATEST_SNAPSHOT'"}'
    
    # Wait for the persistent disk to be created from the disk snapshot
    DISK_STATUS=$(curl -X GET -H "Authorization: Bearer $OAUTH_TOKEN" \
        https://compute.googleapis.com/compute/v1/projects/$PROJECT_NAME/zones/$ZONE_NAME/disks/$LATEST_SNAPSHOT-restored \
        --silent | jq -r .status)
    
    while [ $DISK_STATUS != "READY" ]
    do
        sleep 2
        DISK_STATUS=$(curl -X GET -H "Authorization: Bearer $OAUTH_TOKEN" \
            https://compute.googleapis.com/compute/v1/projects/$PROJECT_NAME/zones/$ZONE_NAME/disks/$LATEST_SNAPSHOT-restored \
            --silent | jq -r .status)
    done
    
    # Attach the new persistent disk created from the snapshot to the VM
    curl -X POST -H "Authorization: Bearer $OAUTH_TOKEN" -H "Content-Type: application/json; charset=utf-8" \
        https://compute.googleapis.com/compute/v1/$ZONE_INFO/instances/$INSTANCE_NAME/attachDisk \
        --data '{ "source": "/compute/v1/'$ZONE_INFO'/disks/'$LATEST_SNAPSHOT'-restored"}'
    
    # Wait for the persistent disk to be attached before mounting
    ATTACH_STATUS=$(curl -X GET -H "Authorization: Bearer $OAUTH_TOKEN" \
        https://compute.googleapis.com/compute/v1/projects/$PROJECT_NAME/zones/$ZONE_NAME/instances/$INSTANCE_NAME \
        --silent | jq '.disks[] | select(.source | contains("disk-"))')
    
    while [ -z "$ATTACH_STATUS" ]
    do
        sleep 2
        ATTACH_STATUS=$(curl -X GET -H "Authorization: Bearer $OAUTH_TOKEN" GET \
            https://compute.googleapis.com/compute/v1/projects/$PROJECT_NAME/zones/$ZONE_NAME/instances/$INSTANCE_NAME \
            --silent | jq '.disks[] | select(.source | contains("disk-"))')
    done
    
    # With the disk attached, mount the disk and restart Apache
    echo UUID=`blkid -s UUID -o value /dev/sdb` /var/www/example.com ext4 discard,defaults,nofail 0 2 \
        | tee -a /etc/fstab
    mount -a
    systemctl reload apache2
    
    # Remove jq so it's not left on the VM
    apt-get remove -y jq
    EOF
    
  8. 문서 시작 부분에서 정의한 NAME_SUFFIX 변수를 app과 같은 시작 스크립트에 적용하려면 envsubst 명령어를 사용합니다.

    export NAME=app
    envsubst '$NAME' < "/opt/cloud-init-scripts/app-startup.sh" \
        | sudo sponge "/opt/cloud-init-scripts/app-startup.sh"
    
  9. VM에 대한 SSH 세션을 종료합니다.

    exit
    
  10. VM의 IP 주소를 가져오고 curl을 사용하여 기본 웹페이지를 확인합니다.

    curl $(gcloud compute instances describe vm-base-$NAME_SUFFIX \
        --zone $ZONE1 \
        --format="value(networkInterfaces.accessConfigs.[0].natIP)")
    

    다음 예시 출력에 표시된 것처럼 기본 웹사이트가 반환됩니다.

    <!doctype html>
    
    <html lang=en>
    <head>
    <meta charset=utf-8>
        <title>HA / DR example</title>
    </head>
    <body>
        <p>Welcome to a test web server with persistent disk snapshots!</p>
    </body>
    </html>
    

    이 단계는 Apache가 올바르게 구성되었고 페이지가 연결된 영구 디스크에서 로드되었는지 확인합니다. 다음 섹션에서는 이 기본 VM을 사용하여 이미지를 만들고 시작 스크립트로 인스턴스 템플릿을 구성합니다.

영구 디스크 스냅샷 일정 만들기

관리형 인스턴스 그룹에서 생성된 VM에 영구 디스크의 최신 데이터가 포함되도록 하려면 스냅샷 일정을 만듭니다. 이 일정은 지정된 시간에 영구 디스크의 자동 스냅샷을 생성하고 스냅샷을 보관할 기간을 관리합니다. 다음 이미지는 이 스냅샷 프로세스의 작동 방법을 보여줍니다.

스냅샷 일정을 지정하는 리소스 정책을 생성하고 이를 영구 디스크에 연결하여 일반 스냅샷을 확보합니다.

스냅샷 생성 빈도에 대한 애플리케이션 요구사항과 비즈니스 목표를 고려해 보세요. 예를 들어 정적 웹사이트에 필요한 스냅샷 빈도는 디스크에 데이터를 쓰는 활성 애플리케이션보다 낮습니다.

고유 애플리케이션의 권장사항을 확인하고 사용할 복구 방법을 결정하기 위해서는 재해 복구 계획 가이드를 참조하세요.

  1. 이 시나리오에서는 스냅샷 일정을 사용하여 일반 영구 디스크 스냅샷을 만듭니다. 이 스냅샷 일정은 리소스 정책에서 정의합니다. 리소스 정책을 사용하면 실행할 작업을 정의하고 환경에서 이러한 작업을 리소스에 연결할 수 있습니다.

    이 리소스 정책의 경우 다음 설정 사용하여 스냅샷을 만드는 일정을 정의합니다.

    • 4시간마다 스냅샷을 만들고 22:00(UTC)부터 시작
    • 스냅샷 1일 보관

    시작 시간 및 스냅샷 생성 빈도와 같은 환경 요구사항에 따라 일정을 구성합니다.

    gcloud compute resource-policies create snapshot-schedule snapshot-schedule-$NAME_SUFFIX \
        --description "Snapshot persistent disk every 4 hours" \
        --max-retention-days 1 \
        --start-time 22:00 \
        --hourly-schedule 4 \
        --region $REGION
    

    자세한 내용은 영구 디스크에 예약된 스냅샷 사용 방법을 참조하세요.

  2. 스냅샷 일정을 사용하려면 리소스 정책을 영구 디스크에 연결합니다. 영구 디스크의 이름과 이전 단계에서 만든 리소스 정책을 지정합니다.

    gcloud compute disks add-resource-policies disk-$NAME_SUFFIX \
        --resource-policies snapshot-schedule-$NAME_SUFFIX \
        --zone $ZONE1
    
  3. 첫 번째 디스크 스냅샷이 생성되지 않으면 이 문서의 나머지 부분을 완료하여 관리형 인스턴스 그룹이 작동하는지 확인할 수 없습니다. 이제 디스크 스냅샷을 직접 만들고 리소스 정책 스냅샷 일정이 다음과 같이 정의된 대로 추가 스냅샷을 생성하도록 합니다.

    gcloud compute disks snapshot disk-$NAME_SUFFIX \
        --zone=$ZONE1 \
        --snapshot-names=disk-$NAME_SUFFIX-$(date "+%Y%m%d%H%M%S")
    

서비스 계정 만들기

다음 단계에서 생성되는 관리형 인스턴스 그룹의 각 VM은 시작 스크립트를 실행해야 합니다. 이 시작 스크립트는 스냅샷에서 영구 디스크를 만든 후 이를 VM에 연결합니다. 보안을 위한 가장 좋은 방법은 이러한 디스크 작업을 실행하는 데 필요한 권한만 가진 새 서비스 계정을 만드는 것입니다. 그런 다음 이 서비스 계정을 VM에 할당합니다.

  1. 관리형 인스턴스 그룹에서 VM으로 사용할 서비스 계정을 만듭니다.

    gcloud iam service-accounts create instance-sa-$NAME_SUFFIX \
        --description="Service account for HA/DR example" \
        --display-name="HA/DR for VM instances"
    
  2. 커스텀 역할을 만들고 디스크 관리 작업을 수행하는 데 필요한 권한만 할당합니다. 다음 권한이 필요합니다.

    • compute.snapshots.list
    • compute.snapshots.useReadOnly
    • compute.disks.get
    • compute.disks.create
    • compute.instances.get
    • compute.instances.attachDisk
    • compute.disks.use
    gcloud iam roles create instance_snapshot_management_$NAME_SUFFIX \
        --project=$PROJECT_ID \
        --title="Snapshot management for VM instances" \
        --description="Custom role to allow an instance to create a persistent disk from a snapshot and attach to VM." \
        --permissions=compute.snapshots.list,compute.snapshots.useReadOnly,compute.disks.get,compute.disks.create,compute.instances.get,compute.instances.attachDisk,compute.disks.use \
        --stage=GA
    
  3. 새 서비스 계정에 필요한 역할 바인딩을 추가합니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:instance-sa-$NAME_SUFFIX@$PROJECT_ID.iam.gserviceaccount.com" \
        --role="projects/$PROJECT_ID/roles/instance_snapshot_management_$NAME_SUFFIX"
    
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:instance-sa-$NAME_SUFFIX@$PROJECT_ID.iam.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
    

VM 이미지 및 인스턴스 템플릿 만들기

필요한 추가 구성 없이 자동으로 배포될 수 있는 동일한 VM을 만들려면 커스텀 VM 이미지를 사용합니다. 이 이미지는 OS 및 Apache 구성을 캡처합니다. 다음 단계에서 관리형 인스턴스 그룹에 생성되는 각 VM에서 이 이미지를 사용합니다.

  1. 이미지를 만들려면 먼저 VM을 중지해야 합니다.

    gcloud compute instances stop vm-base-$NAME_SUFFIX --zone=$ZONE1
    
  2. 이전 섹션에서 구성한 기본 VM의 이미지를 만듭니다.

    gcloud compute images create image-$NAME_SUFFIX \
        --source-disk=vm-base-$NAME_SUFFIX \
        --source-disk-zone=$ZONE1 \
        --storage-location=$REGION
    
  3. cloud-init을 사용하여 관리형 인스턴스 그룹에서 VM이 처음 부팅될 때 이전 시작 스크립트를 실행합니다. VM에 적용된 정기 시작 스크립트는 업데이트 후 VM이 재부팅되는 경우와 같이 VM이 부팅될 때마다 실행됩니다.

    인스턴스 업데이트에 사용할 cloud-init 구성 파일을 만듭니다.

    tee -a cloud-init.yaml >/dev/null <<'EOF'
    #cloud-config
    
    runcmd:
     - [ bash, /opt/cloud-init-scripts/app-startup.sh ]
    EOF
    
  4. cloud-init 구성을 적용하여 스냅샷으로부터 디스크를 만들고 VM에 연결 및 마운트하는 시작 스크립트를 실행하여 인스턴스 템플릿을 만듭니다.

    gcloud compute instance-templates create template-$NAME_SUFFIX \
        --machine-type=n1-standard-1 \
        --subnet=projects/$PROJECT_ID/regions/$REGION/subnetworks/subnet-$NAME_SUFFIX-$REGION \
        --tags=http-server \
        --image=image-$NAME_SUFFIX \
        --scopes cloud-platform \
        --service-account="instance-sa-$NAME_SUFFIX@$PROJECT_ID.iam.gserviceaccount.com" \
        --metadata-from-file user-data=cloud-init.yaml
    

관리형 인스턴스 그룹 만들기

관리형 인스턴스 그룹이 VM을 실행합니다. 관리형 인스턴스 그룹이 정의된 영역에서 실행되고 VM 상태를 모니터링합니다. 장애가 발생하고 VM 실행이 중지되면 관리형 인스턴스 그룹이 동일 영역에서 또 다른 VM을 다시 만들려고 시도하고 최신 스냅샷으로부터 영구 디스크를 만듭니다. 장애가 영역 수준에서 발생하면 콜드 장애 조치를 수동으로 수행하고 다른 영역에서 또 다른 관리형 인스턴스 그룹을 만들어야 합니다. 동일한 커스텀 이미지 및 인스턴스 템플릿이 동일한 방법으로 VM을 자동으로 구성합니다.

  1. 관리형 인스턴스 그룹에서 VM을 모니터링하기 위해 상태 확인을 만듭니다. 이 상태 확인은 포트 80으로 VM이 응답하는지 확인합니다. 자체 애플리케이션의 경우 VM 상태를 확인하기 위해 적합한 포트를 모니터링합니다.

    gcloud compute health-checks create http http-basic-check-$NAME_SUFFIX --port 80
    
  2. VM이 하나만 있는 관리형 인스턴스 그룹을 만듭니다. 이 단일 VM은 최신 스냅샷에서 영구 디스크를 부팅 및 생성한 후 이를 마운트하고 웹 트래픽 제공을 시작합니다.

    gcloud compute instance-groups managed create instance-group-$NAME_SUFFIX-$ZONE1 \
        --base-instance-name=instance-vm-$NAME_SUFFIX \
        --template=template-$NAME_SUFFIX \
        --size=1 \
        --zone=$ZONE1 \
        --health-check=http-basic-check-$NAME_SUFFIX
    

부하 분산기 만들기 및 구성

사용자가 웹사이트에 액세스하기 위해서는 관리형 인스턴스 그룹에서 실행되는 VM으로의 트래픽을 허용해야 합니다. 또한 관리형 인스턴스 그룹에 영역 오류가 발생할 경우 새로운 VM으로 트래픽을 자동으로 리디렉션해야 할 수 있습니다.

다음 섹션에서는 포트 80에서 HTTP 트래픽에 대한 백엔드 서비스를 사용하여 외부 부하 분산기를 만들고, 이전 단계에서 만든 상태 확인을 사용하고, 외부 IP 주소를 백엔드 서비스에 매핑합니다.

자세한 내용은 간단한 외부 HTTP 부하 분산기 설정 방법을 참조하세요.

  1. 애플리케이션의 부하 분산기를 만들고 구성합니다.

    # Configure port rules for HTTP port 80
    gcloud compute instance-groups set-named-ports \
        instance-group-$NAME_SUFFIX-$ZONE1 \
        --named-ports http:80 \
        --zone $ZONE1
    
    # Create a backend service and add the managed instance group to it
    gcloud compute backend-services create \
        web-backend-service-$NAME_SUFFIX \
        --protocol=HTTP \
        --port-name=http \
        --health-checks=http-basic-check-$NAME_SUFFIX \
        --global
    
    gcloud compute backend-services add-backend \
        web-backend-service-$NAME_SUFFIX \
        --instance-group=instance-group-$NAME_SUFFIX-$ZONE1 \
        --instance-group-zone=$ZONE1 \
        --global
    
    # Create a URL map for the backend service
    gcloud compute url-maps create web-map-http-$NAME_SUFFIX \
        --default-service web-backend-service-$NAME_SUFFIX
    
    # Configure forwarding for the HTTP traffic
    gcloud compute target-http-proxies create \
        http-lb-proxy-$NAME_SUFFIX \
        --url-map web-map-http-$NAME_SUFFIX
    
    gcloud compute forwarding-rules create \
        http-content-rule-$NAME_SUFFIX \
        --global \
        --target-http-proxy=http-lb-proxy-$NAME_SUFFIX \
        --ports=80
    
  2. 웹 트래픽에 대한 전달 규칙의 IP 주소를 가져옵니다.

    IP_ADDRESS=$(gcloud compute forwarding-rules describe http-content-rule-$NAME_SUFFIX \
        --global \
        --format="value(IPAddress)")
    
  3. curl을 사용하거나 웹브라우저를 열어 이전 단계의 부하 분산기 IP 주소를 사용하여 웹사이트를 확인합니다.

    curl $IP_ADDRESS
    

    부하 분산기 배포가 완료되고 백엔드로 트래픽을 올바르게 연결하려면 몇 분 정도 걸립니다. 부하 분산기 배포가 계속 수행되면 HTTP 404 또는 502 오류가 반환됩니다. 필요한 경우 몇 분 정도 기다린 후 웹사이트 액세스를 다시 시도합니다.

    다음 예시 출력에 표시된 것처럼 기본 웹사이트가 반환됩니다.

    <!doctype html>
    
    <html lang=en>
    <head>
    <meta charset=utf-8>
        <title>HA / DR example</title>
    </head>
    <body>
        <p>Welcome to a Compute Engine website with warm failover to Cloud Storage!</p>
    </body>
    </html>
    

영역 장애 조치 및 복구 시뮬레이션

영역 수준에서 오류를 시뮬레이션하기 전 리소스 배포를 검토합니다. 모든 리소스는 다음 환경을 지원하도록 생성되었습니다.

외부 애플리케이션 부하 분산기에서 사용자를 관리형 인스턴스 그룹에서 실행되는 단일 VM으로 안내하고, 리소스 정책은 VM에 연결된 영구 디스크의 스냅샷을 정기적으로 생성합니다.

  • 기본 웹사이트를 저장하는 영구 디스크가 연결된 관리형 인스턴스 그룹에서 VM 하나가 실행됩니다.
  • 스냅샷은 리소스 정책 스냅샷 일정을 사용하여 영구 디스크로 생성됩니다.
  • 시작 스크립트는 인스턴스 템플릿에 적용되므로 관리형 인스턴스 그룹에 생성된 모든 VM이 마지막 디스크 스냅샷에서 영구 디스크를 만들어 연결합니다.
  • 상태 확인은 관리형 인스턴스 그룹 내에 있는 VM의 상태를 모니터링합니다.
  • 외부 애플리케이션 부하 분산기가 관리형 인스턴스 그룹에서 실행되는 VM으로 사용자를 연결합니다.
  • VM이 실패하면 관리형 인스턴스 그룹이 동일 영역에 VM을 다시 만들려고 시도합니다. 영역 수준에서 장애가 발생하면 작동 중인 다른 영역에 대체 관리형 인스턴스 그룹을 수동으로 만들어야 합니다.

프로덕션 환경에서는 문제가 발생할 때 Cloud Monitoring 또는 기타 모니터링 솔루션을 통해 알림을 받을 수 있습니다. 이 알림은 작동 중인 다른 영역에 대체 관리형 인스턴스 그룹을 수동으로 만들기 전에 오류 범위를 이해하라는 메시지를 사용자에게 표시합니다. 또 다른 방법은 모니터링 솔루션을 사용하여 관리형 인스턴스 그룹 장애에 자동으로 응답하는 것입니다.

사용자 또는 모니터링 솔루션 측면에서 가장 적절한 조치가 장애 조치를 수행하는 것으로 결정되면 대체 관리형 인스턴스 그룹을 만듭니다. 이 문서에서는 이 대체 리소스를 수동으로 만듭니다.

  1. 영역 수준의 장애를 시뮬레이션하려면 부하 분산기 백엔드와 관리형 인스턴스 그룹을 삭제합니다.

    gcloud compute backend-services remove-backend \
        web-backend-service-$NAME_SUFFIX \
        --instance-group=instance-group-$NAME_SUFFIX-$ZONE1 \
        --instance-group-zone=$ZONE1 \
        --global
    
    gcloud compute instance-groups managed delete instance-group-$NAME_SUFFIX-$ZONE1 \
          --zone=$ZONE1
    

    메시지가 표시되면 관리형 인스턴스 그룹 삭제 요청을 확인합니다.

    그러면 이제 프로덕션 환경에서 모니터링 시스템이 콜드 장애 조치 작업을 요청하는 알림을 생성합니다.

  2. curl 또는 웹브라우저를 다시 사용해서 부하 분산기의 IP 주소에 액세스합니다.

    curl $IP_ADDRESS --max-time 5
    

    부하 분산기에 정상 상태의 대상이 없으므로 curl 요청이 실패합니다.

  3. 콜드 장애 조치를 시뮬레이션하려면 다른 영역에서 관리형 인스턴스 그룹을 만듭니다.

    gcloud compute instance-groups managed create instance-group-$NAME_SUFFIX-$ZONE2 \
        --template=template-$NAME_SUFFIX \
        --size=1 \
        --zone=$ZONE2 \
        --health-check=http-basic-check-$NAME_SUFFIX
    

    VM 이미지, 인스턴스 템플릿 및 영구 디스크는 애플리케이션 인스턴스에 대해 모든 구성을 유지 관리합니다.

  4. 부하 분산기를 업데이트하여 새로운 관리형 인스턴스 그룹 및 VM을 추가합니다.

    gcloud compute instance-groups set-named-ports \
        instance-group-$NAME_SUFFIX-$ZONE2 \
        --named-ports http:80 \
        --zone $ZONE2
    
    gcloud compute backend-services add-backend \
        web-backend-service-$NAME_SUFFIX \
        --instance-group=instance-group-$NAME_SUFFIX-$ZONE2 \
        --instance-group-zone=$ZONE2 \
        --global
    
  5. curl 또는 웹브라우저를 한 번 더 사용하여 관리형 인스턴스 그룹에서 실행되는 VM으로 트래픽을 전달하는 부하 분산기의 IP 주소에 액세스합니다.

    curl $IP_ADDRESS
    

    VM 배포가 완료되고 최신 영구 디스크 스냅샷으로부터 데이터가 복원되는 데 몇 분 정도 걸립니다. VM이 아직 배포 중이면 HTTP 404 또는 502 오류가 반환되고, 데이터가 아직 복원 중이면 기본 Apache가 표시됩니다. 필요한 경우 몇 분 정도 기다린 후 웹사이트 액세스를 다시 시도합니다.

    다음 예시 응답은 VM에서 올바르게 실행되는 웹페이지를 보여줍니다.

    <!doctype html>
    <html lang=en>
    <head>
    <meta charset=utf-8>
        <title>HA / DR example</title>
    </head>
    <body>
        <p>Welcome to a test web server with persistent disk snapshots!</p>
    </body>
    </html>
    
  6. 관리형 인스턴스 그룹의 상태를 확인합니다.

    gcloud compute instance-groups managed list-instances instance-group-$NAME_SUFFIX-$ZONE2 \
        --zone $ZONE2
    

    다음 예시 출력에서는 VM의 상태를 RUNNINGHEALTHY로 표시합니다.

    NAME             ZONE           STATUS   HEALTH_STATE  ACTION
    instance-vm-app  us-central1-f  RUNNING  HEALTHY       NONE
    
  7. 연결된 영구 디스크가 스냅샷에서 생성되었는지 확인하려면 소스를 살펴보세요. 이전 list-instances 명령어에서 표시된 인스턴스 NAME을 지정합니다.

    gcloud compute instances describe NAME \
        --zone=$ZONE2 \
        --format="value(disks.[1].source)"
    

    다음은 영구 디스크 이름이 disk-app-us-central1-a-20210630165529-umopkt17-restored인 예시 출력입니다. -restored 서픽스는 시작 스크립트에 의해 최신 디스크 스냅샷의 이름에 추가됩니다.

    https://www.googleapis.com/compute/v1/projects/project/zones/us-central1-f/disks/disk-app-us-central1-a-20210630165529-umopkt17-restored
    

정리

이 가이드에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

이 문서에서 만든 개별 리소스를 삭제하려면 다음 단계를 수행합니다.

  1. 부하 분산기 구성을 삭제합니다.

    gcloud compute forwarding-rules delete \
        http-content-rule-$NAME_SUFFIX --global --quiet
    
    gcloud compute target-http-proxies delete \
        http-lb-proxy-$NAME_SUFFIX --quiet
    
    gcloud compute url-maps delete web-map-http-$NAME_SUFFIX --quiet
    
    gcloud compute backend-services delete \
        web-backend-service-$NAME_SUFFIX --global --quiet
    
  2. 관리형 인스턴스 그룹 및 상태 확인을 삭제합니다.

    gcloud compute instance-groups managed delete instance-group-$NAME_SUFFIX-$ZONE2 \
        --zone=$ZONE2 --quiet
    
    gcloud compute health-checks delete http-basic-check-$NAME_SUFFIX --quiet
    
  3. 인스턴스 템플릿, cloud-init 구성, 기본 VM 영구 디스크, 스냅샷 일정을 삭제합니다.

    gcloud compute instance-templates delete template-$NAME_SUFFIX --quiet
    
    rm cloud-init.yaml
    
    gcloud compute images delete image-$NAME_SUFFIX --quiet
    
    gcloud compute instances delete vm-base-$NAME_SUFFIX --zone=$ZONE1 --quiet
    
    gcloud compute disks delete disk-$NAME_SUFFIX --zone=$ZONE1 --quiet
    
    gcloud compute resource-policies delete \
        snapshot-schedule-$NAME_SUFFIX --region $REGION --quiet
    
  4. 인스턴스가 만든 스냅샷과 디스크를 나열한 후 삭제합니다.

    gcloud compute disks list --filter="name:disk-$NAME_SUFFIX" \
        --uri | xargs gcloud compute disks delete
    
    gcloud compute snapshots list --filter="name:disk-$NAME_SUFFIX" \
        --uri | xargs gcloud compute snapshots delete
    
  5. 커스텀 역할 및 서비스 계정을 삭제합니다.

    gcloud iam roles delete instance_snapshot_management_$NAME_SUFFIX \
      --project=$PROJECT_ID --quiet
    
    gcloud iam service-accounts delete \
        instance-sa-$NAME_SUFFIX@$PROJECT_ID.iam.gserviceaccount.com --quiet
    
  6. 방화벽 규칙을 삭제합니다.

    gcloud compute firewall-rules delete allow-health-check-$NAME_SUFFIX --quiet
    
    gcloud compute firewall-rules delete allow-ssh-$NAME_SUFFIX --quiet
    
    gcloud compute firewall-rules delete allow-http-$NAME_SUFFIX --quiet
    
  7. 서브넷 및 VPC를 삭제합니다.

    gcloud compute networks subnets delete \
        subnet-$NAME_SUFFIX-$REGION --region=$REGION --quiet
    
    gcloud compute networks delete network-$NAME_SUFFIX --quiet
    

다음 단계