개요

현재 블로그를 두 플랫폼을 통해 운영 중이다.
하나는 Github Pages를 활용한 블로그, 나머지 하나는 Oracle Freetier 서버를 활용한 블로그이다.
Github 블로그는 구축도 쉽고 신경 쓸 것이 많이 없지만 오라클 프리티어는 직접 호스팅을 하는 것이다
보니 생각 보다 신경쓸 것도 많다.

하지만 직접 호스팅인 만큼 자유도가 상당하기 때문에 이것저것 새로운 기능을 테스트하거나
개인 토이 프로젝트를 진행할 때 개발 서버로 역할도 충분하다고 생각한다.
이번에 인스턴스 생성을 시도하게 된 것도 토이 프로젝트와 블로그 모니터링 용도로 활용하기 위해서였다.

오라클 프리티어의 경우, 평생 무료인 인스턴스와 일정 사용량 이하는 무료로 제공되는 인스턴스가 있다.
평생 무료의 경우도 쓸만은 하지만 아무래도 저스펙이기 때문에 활용면에서 조금 부족한 감이 있다.
그래서 평생 무료가 아닌 A1 Spec으로 생성을 시도했었다.


작업 내용

Oracle Freetier A1
오라클 프리티어 인스턴스 생성을 할 때 스펙을 설정할 수 있는데 위 이미지와 같이 A1의 경우는
최대 CPU 4, Memory 24G까지 사용할 수 있다고 되어있다.
A1이 제공되기 시작한 초기에 CPU 2, Mem 12G로 1개 인스턴스를 생성해두었었고 남은 제공량을
활용해서 새로운 인스턴스 생성을 시도하였다.


하지만 서울 리전이기 때문에 이미 사용량이 가득 찼다는 에러와 함꼐 생성이 되지 않았다.
예전에도 서울 리전에서 생성하기가 정말 어려웠었던 기억이 있는데 현재는 정말 생성하기가 어렵다고 한다.
그래서 방법이 없을까 찾아보던 중 파이썬을 활용해서 자동화가 가능한 것을 확인했다.

바로 코드를 수정해서 테스트 해보았고 조금만 커스텀하면 되곘다 싶어서 수정 작업을 진행했다.
아래는 텔레그램으로 결과를 보내주는 아주 간단한 커스텀만 해둔 코드이다.
원본 코드는 아래 블로그에서 확인 할 수 있다.
오라클 A1 인스턴스 생성 with python

# inspired by https://github.com/jaehwan1912/oci_instance_creation_script
import requests
from oci.signer import Signer
import time
from datetime import datetime
import telegram
import asyncio

endpoint = 'https://iaas.ap-seoul-1.oraclecloud.com/20160918/instances/'
auth = Signer(
    tenancy="{{tenancy}}",
    user="{{user}}",
    fingerprint="{{fingerprint}}",
    private_key_file_location="{{key_file_path}}"
)


def makeit():
    # body
    body = {
        "metadata":{
            "ssh_authorized_keys":"{{ssh_ras_key}}"
        },
        "shape":"VM.Standard.A1.Flex",
        "compartmentId":"{{compartmentId}}",
        "displayName":"{{instance_name}}",
        "availabilityDomain":"WIUm:AP-SEOUL-1-AD-1",
        "sourceDetails":{
            "sourceType":"image",
            "imageId":"{{ImageId}}"
        },
        "createVnicDetails":{
            "assignPublicIp":"true",
            "subnetId":"{{subnetId}}",
            "assignPrivateDnsRecord":"true",
            "assignIpv6Ip":"false"
        },
        "agentConfig":{
            "pluginsConfig":[
                {
                    "name":"Vulnerability Scanning",
                    "desiredState":"DISABLED"
                },
                {
                    "name":"Management Agent",
                    "desiredState":"DISABLED"
                },
                {
                    "name":"Custom Logs Monitoring",
                    "desiredState":"ENABLED"
                },
                {
                    "name":"Compute RDMA GPU Monitoring",
                    "desiredState":"DISABLED"
                },
                {
                    "name":"Compute Instance Monitoring",
                    "desiredState":"ENABLED"
                },
                {
                    "name":"Compute HPC RDMA Auto-Configuration",
                    "desiredState":"DISABLED"
                },
                {
                    "name":"Compute HPC RDMA Authentication",
                    "desiredState":"DISABLED"
                },
                {
                    "name":"Block Volume Management",
                    "desiredState":"DISABLED"
                },
                {
                    "name":"Bastion",
                    "desiredState":"DISABLED"
                }
            ],
            "isMonitoringDisabled":"false",
            "isManagementDisabled":"false"
        },
        "definedTags":{
            
        },
        "freeformTags":{
            
        },
        "instanceOptions":{
            "areLegacyImdsEndpointsDisabled":"false"
        },
        "availabilityConfig":{
            "recoveryAction":"RESTORE_INSTANCE"
        },
        "shapeConfig":{
            "ocpus":2,
            "memoryInGBs":12
        }
    }

    return requests.post(endpoint, json=body, auth=auth)

def sendTelegram(msg, count) :
    bot = telegram.Bot('{{telegram_key}}')
    chat_id = {{telegram_chat_id}}

    output = "---------------------------------------\n"
    output += f"{count} try.. {msg} Oracle Freetier A1\n"
    output += "---------------------------------------\n"

    print(f"{output}")
    asyncio.run(bot.send_message(chat_id = chat_id, text = output))

if __name__=='__main__':
    error_msg = "Out of host capacity."
    run = 1
    count = 0
    while(run):
        res = makeit()
        if res.status_code == 500:
            if error_msg == res.json()["message"]:
                print(datetime.now(), error_msg)
                sendTelegram("Failed", count)
                time.sleep(120)
                count = count + 1
            else:
                print(res.json())
                sendTelegram("Error", count)
                run = 0
        else:
            print(res.json())
            sendTelegram("Success", count)
            run = 0

빈칸('{{ }}')으로 보이는 항목은 각자의 정보로 새로 수정해서 사용하면 된다.

auth = Signer() 부분 정보를 얻는 방법은 여기에 기술하기에는 내용이
길어길 것 같아서 우선은 참고 링크만 남겨둔다.(추후 따로 정리하거나 이 페이지에 업데이트 예정)

오라클 클라우드 Out of host capacity 오류, 그리고 스크립트로 뚫기

Body 부분의 정보는 개발자 도구로 손 쉽게 확인이 가능하다.
개발자 도구를 켠 후 Create 버튼을 누르면 잡히는 API의 Payload 값에 모두 담겨있다.

Dev Tools

위 값을 복사에서 코드에 붙여넣고 사용하기만 하면 된다.
여기까지 되었다면 스크립트는 준비가 되었고 실제 동작시키기만 하면 된다.
PC를 사용할 때만 동작시켜서 성공한 사람도 있고 서버 등을 이용해서
계속 동작시키는 사람도 있고 다양하다.
필자는 이미 기존에 인스턴스가 하나 있기 때문에 해당 서버에서 동작시켰다.
너무 자주 시도하면 아예 막힌다는 얘기도 있기 때문에 시간 설정은 각자 판단하게 하면 될 것 같다.


후기

약 3주간 15,000번의 시도를 해보았는데 성공하지는 못하였다.

텔레그램 코드쪽에 예외처리가 부족해서 그런지 중간중간 Timeout 발생하면서 스크립트가
종료되기도 했고 API 응답으로 “Out of host capacity.“가 아닌 텍스트가 넘어오는 경우도 있었었다.
결론적으로는 스크립트가 불완전한 상태이다. 하지만 그래도 손으로 직접하는 것 보다는 훨씬 효율이 좋고
서버를 활용하면 자고 있는 시간에도 시도하기 때문에 언젠가는 되지 않을까 하는 마음으로 ..
나중에 시간이 될 때 스크립트는 보완작업 예정이다.


참고 링크

오라클 클라우드 Out of host capacity 오류, 그리고 스크립트로 뚫기
[Python] 텔레그램 봇 생성 및 메시지 송신
오라클 A1 인스턴스 생성 with python