{"id":2988,"date":"2025-03-15T23:52:51","date_gmt":"2025-03-15T14:52:51","guid":{"rendered":"https:\/\/manvscloud.com\/?p=2988"},"modified":"2025-03-15T23:52:51","modified_gmt":"2025-03-15T14:52:51","slug":"ncloud-%ea%b4%80%eb%a6%ac%ed%98%95-%eb%8d%b0%ec%9d%b4%ed%84%b0%eb%b2%a0%ec%9d%b4%ec%8a%a4%ec%9d%98-%eb%b0%b1%ec%97%85-%ec%8b%a4%ed%8c%a8-%eb%8d%94-%ec%9d%b4%ec%83%81-%eb%86%93%ec%b9%98%ec%a7%80","status":"publish","type":"post","link":"https:\/\/manvscloud.com\/?p=2988","title":{"rendered":"[NCLOUD] \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc758 \ubc31\uc5c5 \uc2e4\ud328, \ub354 \uc774\uc0c1 \ub193\uce58\uc9c0 \ub9c8\uc138\uc694!"},"content":{"rendered":"\n<p>\uc548\ub155\ud558\uc138\uc694 MANVSCLOUD \uae40\uc218\ud604\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\ucd5c\uadfc \uc6b4\uc601\ud558\uace0 \uc788\ub294 Cloud DB for PostgreSQL\uc5d0\uc11c \uc9c0\uc18d\uc801\uc778 \ubc31\uc5c5 \uc2e4\ud328\uac00 \ubc1c\uc0dd\ud558\ub294 \ubb38\uc81c\uac00 \uc788\uc5c8\uc2b5\ub2c8\ub2e4. Cloud DB for PostgreSQL\uc740 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub85c \ubc31\uc5c5 \ubcf4\uad00\uc77c\uacfc \ubc31\uc5c5 \uc2dc\uac04\uc744 \uc124\uc815\ud560 \uc218 \uc788\ub294 \ud3b8\ub9ac\ud55c \uae30\ub2a5\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4. <\/p>\n\n\n\n<p>\ud558\uc9c0\ub9cc \uc124\uc815\ud55c \uc2dc\uac04\ub300\uc5d0 \ubc31\uc5c5\uc774 \uc81c\ub300\ub85c \uc774\ub8e8\uc5b4\uc9c0\uc9c0 \uc54a\uc544 1\uc77c 1\ubc31\uc5c5\uc774 \ub418\uc9c0 \uc54a\uace0 \uc694\uad6c\ub418\ub294 \ubc31\uc5c5 \ubcf4\uad00\uc77c\ub9cc\ud07c \ub370\uc774\ud130\uac00 \ubcf4\uad00\ub418\uc9c0 \uc54a\ub294 \ubb38\uc81c\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\ub370\uc774\ud130\ub294 \uc2dc\uc2a4\ud15c \uc6b4\uc601\uc5d0\uc11c \uac00\uc7a5 \uc911\uc694\ud55c \uc790\uc0b0 \uc911 \ud558\ub098\uc774\uba70 \ubc31\uc5c5\uc740 \uc774\ub97c \ubcf4\ud638\ud558\ub294 \ucd5c\ud6c4\uc758 \ubcf4\ub8e8\uc785\ub2c8\ub2e4. \ub530\ub77c\uc11c \uc624\ub298\uc740 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \ubc31\uc5c5\uc758 \uc131\uacf5\/\uc2e4\ud328 \uc5ec\ubd80\ub97c \ud6a8\uacfc\uc801\uc73c\ub85c \ubaa8\ub2c8\ud130\ub9c1\ud560 \uc218 \uc788\ub294 \uc54c\ub9bc \uae30\ub2a5\uc744 \uad6c\ud604\ud558\ub294 \ubc29\ubc95\uc744 \uacf5\uc720\ub4dc\ub9ac\uace0\uc790 \ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-white-color has-vivid-green-cyan-background-color has-text-color has-background has-link-color wp-elements-8e4044c694945b9623cde124f259c7fd\"> \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub3c4 \ubc31\uc5c5\uc5d0 \uc2e4\ud328\ud560 \uc218 \uc788\ub2e4<\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"560\" src=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100510\/image-1-1024x560.png\" alt=\"\" class=\"wp-image-2995\" srcset=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100510\/image-1-1024x560.png 1024w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100510\/image-1-300x164.png 300w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100510\/image-1-768x420.png 768w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100510\/image-1-1080x591.png 1080w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100510\/image-1.png 1432w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c\ub294 \uc704 \uc774\ubbf8\uc9c0\uc640 \uac19\uc774 \ubc31\uc5c5 \ubcf4\uad00\uc77c\uacfc \ubc31\uc5c5 \uc2dc\uac04\uc744 \uc9c0\uc815\ud574\uc904 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774\ub860\uc801\uc73c\ub85c\ub294 \ub9e4\uc77c \uc9c0\uc815\ud55c \uc2dc\uac04\ub300\uc5d0 \ubc31\uc5c5\uc774 \uc218\ud589\ub418\uba70 \uc124\uc815\ub41c \ubcf4\uad00\uc77c\ub9cc\ud07c \ubc31\uc5c5 \ub370\uc774\ud130\uac00 \uc548\uc804\ud558\uac8c \ubcf4\uad00\ub418\uc5b4\uc57c \ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"463\" src=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100558\/image-2-1024x463.png\" alt=\"\" class=\"wp-image-2996\" srcset=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100558\/image-2-1024x463.png 1024w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100558\/image-2-300x136.png 300w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100558\/image-2-768x347.png 768w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100558\/image-2-1536x695.png 1536w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100558\/image-2-1080x488.png 1080w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100558\/image-2.png 1842w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>(\uc120\uc0dd\ub2d8&#8230; \uc81c \ubc31\uc5c5\uc740 \uc5b4\ub514\ub85c \uac04 \uac83\uc785\ub2c8\uae4c? \ubc31\uc5c5 \uc2dc\uac04\uc740 \ubb34\uc2a8 \uc77c\uc774 \uc788\uc5c8\ub358 \uac81\ub2c8\uae4c?&#8230;)<\/p>\n\n\n\n<p>\ud558\uc9c0\ub9cc \uc5b4\ub290 \ub0a0 Backup \ub9ac\uc2a4\ud2b8\ub97c \ud655\uc778\ud574\ubcf4\ub2c8 \ubc31\uc5c5 \ub0a0\uc9dc\uac00 \ub744\uc5c4\ub744\uc5c4 \ub204\ub77d\ub418\uc5b4 \uc788\ub294 \ud604\uc0c1\uc744 \ubc1c\uacac\ud588\uc2b5\ub2c8\ub2e4. <\/p>\n\n\n\n<p>\ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc6a9\ub7c9\uc774 \ub108\ubb34 \ucee4\uc11c \ubc31\uc5c5 \uc18c\uc694 \uc2dc\uac04\uc774 \uae38\uc5b4\uc838 \ub2e4\uc74c\ub0a0\ub85c \ubbf8\ub8e8\uc5b4\uc9c4 \uac83\ub3c4 \uc544\ub2c8\uc5c8\uc2b5\ub2c8\ub2e4. (5GB\ub3c4 \uc548\uc4f0\uace0 \uc788\ub2e4\uace0&#8230;)<\/p>\n\n\n\n<p>\uc6b0\uc120 \ud558\ub8e8\uc5d0 \ud55c \ubc88\uc529 \ubc31\uc5c5\uc774 \uc81c\ub300\ub85c \uc218\ud589\ub418\uc5c8\ub294\uc9c0 \ubaa8\ub2c8\ud130\ub9c1\uc774 \ub420 \ud544\uc694\uac00 \uc788\uc5c8\uc2b5\ub2c8\ub2e4. \uadf8\ub7ec\ub098 \ub9e4\ubc88 \ucf58\uc194\uc5d0 \uc811\uc18d\ud574\uc11c \ubc31\uc5c5 \uc0c1\ud0dc\ub97c \ud655\uc778\ud558\ub294 \uac83\uc740 \ub9e4\uc6b0 \ubc88\uac70\ub86d\uace0 \uc2dc\uac04 \uc18c\ubaa8\uc801\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\uc800\ub294 \ub9e4\uc77c \uc544\uce68 \ucd9c\uadfc\uacfc \ub3d9\uc2dc\uc5d0 \ud544\uc694\ud55c \ud56d\ubaa9\ub4e4\uc744 \uc6b0\uc120\uc801\uc73c\ub85c \uccb4\ud06c\ud558\ub294 \ud3b8\uc785\ub2c8\ub2e4. \ub530\ub77c\uc11c \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \ubc31\uc5c5\ub3c4 \ub9e4\uc77c \uc544\uce68\ub9c8\ub2e4 \uc131\uacf5\uc801\uc73c\ub85c \uc218\ud589\ub418\uc5c8\ub294\uc9c0 Slack\uc73c\ub85c \uc54c\ub9bc\uc744 \ubc1b\uc544\ubcfc \uc218 \uc788\ub3c4\ub85d \ud588\uc2b5\ub2c8\ub2e4. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-white-color has-vivid-green-cyan-background-color has-text-color has-background has-link-color wp-elements-98e41e1248a12e8cc9ccceb79ebad856\"> \ubc31\uc5c5 \uc5ec\ubd80 \uc9c0\ucf1c\ubcf4\uace0 \uc788\ub2e4<\/h3>\n\n\n\n<p>\uc790\ub3d9\ud654 \uc2dc\uc2a4\ud15c\uc744 \uad6c\ud604\ud558\uae30 \uc704\ud574 Cloud Functions\uc744 \ud65c\uc6a9\ud558\uaca0\uc2b5\ub2c8\ub2e4. \uc774\ub7f0 \uac04\ub2e8\ud55c \uae30\ub2a5\uc744 \uad6c\ud604\ud558\uace0 \uc790\ub3d9\ud654\ud558\ub294 \ubd80\ubd84\uc740 \uc5ed\uc2dc Serverless\uac00 \ubca0\uc2a4\ud2b8 \uc120\ud0dd\uc9c0\uc785\ub2c8\ub2e4. \uc778\ud504\ub77c \uad00\ub9ac \ubd80\ub2f4 \uc5c6\uc774 \ud544\uc694\ud55c \uae30\ub2a5\ub9cc \uc9d1\uc911\uc801\uc73c\ub85c \uad6c\ud604\ud560 \uc218 \uc788\uc5b4\uc11c \uc81c\uac00 \uc544\uc8fc \uc88b\uc544\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\uae34 \ub9d0\ud558\uc9c0 \uc54a\uace0 \ucf54\ub4dc\ubd80\ud130 \uacf5\uc720\ub4dc\ub824 \ubcf4\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\uba3c\uc800 \uad6c\ud604 \ud658\uacbd\uc740 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4:<br>&#8211; <strong>Python 3.11<\/strong><br>&#8211; <strong>Trigger: Cron<\/strong> (\uc54c\ub9bc\uc744 \uc6d0\ud558\ub294 \uc2dc\uac04\ub300\ub85c \uc124\uc815)<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import hashlib\nimport hmac\nimport base64\nimport requests\nimport time\nimport json\nimport re\nfrom datetime import datetime, timezone, timedelta\n\ndef parse_datetime(date_str):\n    \"\"\"\ub2e4\uc591\ud55c \ud615\uc2dd\uc758 \ub0a0\uc9dc \ubb38\uc790\uc5f4\uc744 \ud30c\uc2f1\ud558\uc5ec datetime \uac1d\uccb4\ub85c \ubcc0\ud658\"\"\"\n    # 2025-02-20T12:08:21+0900 \ud615\uc2dd \ud30c\uc2f1\n    if '+0900' in date_str:\n        pattern = r'(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})\\+0900'\n        match = re.match(pattern, date_str)\n        if match:\n            base_dt = datetime.strptime(match.group(1), '%Y-%m-%dT%H:%M:%S')\n            return base_dt.replace(tzinfo=timezone(timedelta(hours=9)))\n    \n    # Z\ub85c \ub05d\ub098\ub294 \uacbd\uc6b0 (UTC)\n    if date_str.endswith('Z'):\n        base_dt = datetime.strptime(date_str[:-1], '%Y-%m-%dT%H:%M:%S')\n        return base_dt.replace(tzinfo=timezone.utc).astimezone(timezone(timedelta(hours=9)))\n    \n    # \ub2e4\ub978 ISO \ud615\uc2dd \uc2dc\ub3c4\n    try:\n        formats = [\n            '%Y-%m-%dT%H:%M:%S',\n            '%Y-%m-%d %H:%M:%S',\n            '%Y-%m-%d'\n        ]\n        \n        for fmt in formats:\n            try:\n                return datetime.strptime(date_str, fmt).replace(tzinfo=timezone(timedelta(hours=9)))\n            except ValueError:\n                continue\n        \n        # \ubaa8\ub4e0 \ud615\uc2dd \uc2e4\ud328 \uc2dc \ub9c8\uc9c0\ub9c9 \uc2dc\ub3c4\n        return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S%z')\n    except ValueError:\n        raise ValueError(f\"\uc9c0\uc6d0\ud558\uc9c0 \uc54a\ub294 \ub0a0\uc9dc \ud615\uc2dd\uc785\ub2c8\ub2e4: {date_str}\")\n\ndef format_datetime(date_str):\n    \"\"\"ISO \ud615\uc2dd\uc758 \ub0a0\uc9dc \ubb38\uc790\uc5f4\uc744 '\ub144 \uc6d4 \uc77c, \uc2dc \ubd84 \ucd08' \ud615\uc2dd\uc73c\ub85c \ubcc0\ud658\"\"\"\n    dt = parse_datetime(date_str)\n    return dt.strftime('%Y\ub144 %m\uc6d4 %d\uc77c, %H\uc2dc %M\ubd84 %S\ucd08')\n\ndef check_backup_status(backup_info):\n    \"\"\"\ubc31\uc5c5 \uc0c1\ud0dc\ub97c \ud655\uc778\ud558\uace0 Slack \uba54\uc2dc\uc9c0 \uc791\uc131\"\"\"\n    today = datetime.now(timezone(timedelta(hours=9))).date()\n    today_str = today.strftime('%Y\ub144 %m\uc6d4 %d\uc77c')\n    \n    messages = []\n    \n    for db in backup_info['getCloudPostgresqlBackupListResponse']['cloudPostgresqlBackupList']:\n        service_name = db['cloudPostgresqlServiceName']\n        backup_time = db.get('backupTime', '\ub79c\ub364')\n        last_backup_str = db['lastBackupDate']\n        \n        # parse_datetime \ud568\uc218\ub97c \uc0ac\uc6a9\ud558\uc5ec \ub0a0\uc9dc \ud30c\uc2f1\n        last_backup_dt = parse_datetime(last_backup_str)\n        last_backup_date = last_backup_dt.date()\n        \n        # \uc624\ub298 \ubc31\uc5c5 \uc5ec\ubd80 \ud655\uc778\n        is_backup_today = (last_backup_date == today)\n        status = \"\uc131\uacf5\" if is_backup_today else \"\uc2e4\ud328\"\n        \n        # Slack \uba54\uc2dc\uc9c0 \uc791\uc131\n        message = {\n            \"blocks\": [\n                {\n                    \"type\": \"section\",\n                    \"text\": {\n                        \"type\": \"mrkdwn\",\n                        \"text\": f\"*\ub370\uc774\ud130\ubca0\uc774\uc2a4 \ubc31\uc5c5 \uc0c1\ud0dc \uc54c\ub9bc*\"\n                    }\n                },\n                {\n                    \"type\": \"divider\"\n                },\n                {\n                    \"type\": \"section\",\n                    \"fields\": [\n                        {\n                            \"type\": \"mrkdwn\",\n                            \"text\": f\"*\uc624\ub298 \ub0a0\uc9dc:*\\n{today_str}\"\n                        },\n                        {\n                            \"type\": \"mrkdwn\",\n                            \"text\": f\"*DB \uc11c\ube44\uc2a4\uba85:*\\n{service_name}\"\n                        },\n                        {\n                            \"type\": \"mrkdwn\",\n                            \"text\": f\"*\uc608\uc57d \ubc31\uc5c5 \uc2dc\uac04:*\\n{backup_time}\"\n                        },\n                        {\n                            \"type\": \"mrkdwn\",\n                            \"text\": f\"*\ucd5c\uc885 \ubc31\uc5c5 \uc2dc\uac04:*\\n{format_datetime(last_backup_str)}\"\n                        },\n                        {\n                            \"type\": \"mrkdwn\",\n                            \"text\": f\"*\uc77c\uc77c \ubc31\uc5c5 \uc5ec\ubd80:*\\n{status}\"\n                        }\n                    ]\n                }\n            ]\n        }\n        \n        # \ubc31\uc5c5 \uc2e4\ud328 \uc2dc \uc0c9\uc0c1 \ud45c\uc2dc\n        if not is_backup_today:\n            message[\"attachments\"] = [\n                {\n                    \"color\": \"#FF0000\",\n                    \"blocks\": [\n                        {\n                            \"type\": \"section\",\n                            \"text\": {\n                                \"type\": \"mrkdwn\",\n                                \"text\": \"\u26a0\ufe0f *\uacbd\uace0: \uc624\ub298 \ubc31\uc5c5\uc774 \uc218\ud589\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4!*\"\n                            }\n                        }\n                    ]\n                }\n            ]\n        \n        messages.append(message)\n    \n    return messages\n\ndef send_to_slack(messages, webhook_url):\n    \"\"\"Slack \uc6f9\ud6c5 URL\ub85c \uba54\uc2dc\uc9c0 \uc804\uc1a1\"\"\"\n    results = []\n    \n    for message in messages:\n        response = requests.post(\n            webhook_url,\n            data=json.dumps(message),\n            headers={'Content-Type': 'application\/json'}\n        )\n        \n        result = {\n            \"status_code\": response.status_code,\n            \"success\": response.status_code == 200,\n            \"response\": response.text\n        }\n        \n        results.append(result)\n    \n    return results\n\ndef get_cloud_postgresql_backup_list(access_key, secret_key):\n    \"\"\"\ub124\uc774\ubc84 \ud074\ub77c\uc6b0\ub4dc API\ub97c \ud1b5\ud574 PostgreSQL \ubc31\uc5c5 \ubaa9\ub85d\uc744 \uac00\uc838\uc634\"\"\"\n    timestamp = str(int(time.time() * 1000))\n    secret_key = bytes(secret_key, 'UTF-8')\n    method = \"GET\"\n    api_server = \"https:\/\/ncloud.apigw.ntruss.com\"\n    uri = \"\/vpostgresql\/v2\/getCloudPostgresqlBackupList\"\n    uri = uri + f\"?responseFormatType=json\"\n    \n    # \uc11c\uba85 \uc0dd\uc131\n    message = method + \" \" + uri + \"\\n\" + timestamp + \"\\n\" + access_key\n    message = bytes(message, 'UTF-8')\n    signingKey = base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())\n    \n    # HTTP \ud5e4\ub354 \uc124\uc815\n    http_header = {\n        'x-ncp-apigw-signature-v2': signingKey,\n        'x-ncp-apigw-timestamp': timestamp,\n        'x-ncp-iam-access-key': access_key,\n    }\n    \n    # API \uc694\uccad \ubc0f \uc751\ub2f5 \ucc98\ub9ac\n    response = requests.get(api_server + uri, headers=http_header)\n    \n    if response.status_code != 200:\n        raise Exception(f\"API \uc694\uccad \uc624\ub958: {response.status_code}, {response.text}\")\n    \n    return response.json()\n\ndef main(args):\n    \"\"\"Cloud Functions \uba54\uc778 \ud568\uc218\"\"\"\n    # \ud544\uc218 \ud30c\ub77c\ubbf8\ud130 \ud655\uc778\n    required_params = ['DB_ACCESS_KEY', 'DB_SECRET_KEY', 'SLACK_WEBHOOK_URL']\n    for param in required_params:\n        if not args.get(param):\n            return {\n                \"statusCode\": 400,\n                \"body\": f\"\ud544\uc218 \ud30c\ub77c\ubbf8\ud130\uac00 \ub204\ub77d\ub418\uc5c8\uc2b5\ub2c8\ub2e4: {param}\"\n            }\n    \n    try:\n        # \ubc31\uc5c5 \uc815\ubcf4 \uac00\uc838\uc624\uae30\n        backup_info = get_cloud_postgresql_backup_list(\n            args.get('DB_ACCESS_KEY'),\n            args.get('DB_SECRET_KEY')\n        )\n        \n        # \ubc31\uc5c5 \uc0c1\ud0dc \ud655\uc778 \ubc0f Slack \uba54\uc2dc\uc9c0 \uc0dd\uc131\n        slack_messages = check_backup_status(backup_info)\n        \n        # Slack\uc73c\ub85c \uba54\uc2dc\uc9c0 \uc804\uc1a1\n        slack_results = send_to_slack(slack_messages, args.get('SLACK_WEBHOOK_URL'))\n        \n        return {\n            \"statusCode\": 200,\n            \"body\": {\n                \"message\": \"\ubc31\uc5c5 \uc0c1\ud0dc \ud655\uc778 \ubc0f \uc54c\ub9bc \uc804\uc1a1 \uc644\ub8cc\",\n                \"backup_count\": len(backup_info['getCloudPostgresqlBackupListResponse']['cloudPostgresqlBackupList']),\n                \"slack_results\": slack_results\n            }\n        }\n    \n    except Exception as e:\n        return {\n            \"statusCode\": 500,\n            \"body\": f\"\uc624\ub958 \ubc1c\uc0dd: {str(e)}\"\n        }<\/pre>\n\n\n\n<p>\uc704 \ucf54\ub4dc\ub294 Cloud DB For PostgreSQL\uc758 \ubc31\uc5c5 \uc131\uacf5\/\uc2e4\ud328 \uc5ec\ubd80\ub97c \ud655\uc778\ud558\uace0 \uc6f9\ud6c5\uc73c\ub85c \uacb0\uacfc\ub97c \uc804\ub2ec\ud558\ub294 \uae30\ub2a5\uc744 \uc218\ud589\ud569\ub2c8\ub2e4. \ub2e4\ub978 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \uc0ac\uc6a9\ud558\uace0 \uc788\uc744 \uacbd\uc6b0 API \uc8fc\uc18c \ubc0f \ud30c\ub77c\ubbf8\ud130\ub97c \uc801\uc808\ud788 \ubcc0\uacbd\ud558\uc5ec \uc0ac\uc6a9\ud558\uc2e4 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<ul>\n<li>\ub514\ud3f4\ud2b8 \ud30c\ub77c\ubbf8\ud130<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"DB_ACCESS_KEY\": \"ACCESS_KEY\",\n  \"DB_SECRET_KEY\": \"SECRET_KEY\",\n  \"SLACK_WEBHOOK_URL\": \"WEBHOOK_URL\"\n}<\/pre>\n\n\n\n<ol>\n<li><strong>ACCESS_KEY<\/strong>: DB \ubc31\uc5c5 \ub9ac\uc2a4\ud2b8\ub97c \uc870\ud68c\ud560 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc788\ub294 ACCESS_KEY<\/li>\n\n\n\n<li><strong>SECRET_KEY<\/strong>: DB \ubc31\uc5c5 \ub9ac\uc2a4\ud2b8\ub97c \uc870\ud68c\ud560 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc788\ub294 ACCESS_KEY\uc758 SECRET_KEY<\/li>\n\n\n\n<li><strong>WEBHOOK_URL<\/strong>: \uaf2d SLACK WEBHOOK URL\ubfd0\ub9cc \uc544\ub2c8\ub77c \uc6d0\ud558\ub294 WEBHOOK URL\uc744 \ub123\uc5b4\uc8fc\uc2dc\uba74 \ub429\ub2c8\ub2e4. MS Teams\ub098 Discord \ub4f1 \ub2e4\ub978 \uba54\uc2e0\uc800 \uc11c\ube44\uc2a4\uc758 \uc6f9\ud6c5 URL\ub3c4 \ud65c\uc6a9 \uac00\ub2a5\ud569\ub2c8\ub2e4.<\/li>\n<\/ol>\n\n\n\n<p>\uc774 Cloud Function\uc740 \ub9e4\uc77c \uc9c0\uc815\ud55c \uc2dc\uac04\uc5d0 \uc2e4\ud589\ub418\uc5b4 \uc804\ub0a0\uc758 \ubc31\uc5c5 \uc0c1\ud0dc\ub97c \ud655\uc778\ud558\uace0 \uadf8 \uacb0\uacfc\ub97c Slack \ucc44\ub110\ub85c \uc804\uc1a1\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"959\" src=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100138\/image-1024x959.png\" alt=\"\" class=\"wp-image-2993\" srcset=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100138\/image-1024x959.png 1024w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100138\/image-300x281.png 300w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100138\/image-768x720.png 768w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100138\/image-1080x1012.png 1080w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2025\/03\/14100138\/image.png 1315w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\uc800\ub294 cron \ud2b8\ub9ac\uac70\ub97c \uc774\uc6a9\ud558\uc5ec \ucd9c\uadfc \uc2dc\uac04\uc5d0 \uc54c\ub9bc\uc744 \ubc1b\ub294 \ubc29\uc2dd\uc744 \uc120\ud0dd\ud588\ub294\ub370 \uc6d0\ud558\ub294 \ud2b8\ub9ac\uac70 \ubc29\uc2dd\uc774 \uc788\ub2e4\uba74 \ubcc0\uacbd\ud574\uc11c \uc0ac\uc6a9\ud574\ub3c4 \uc88b\uc2b5\ub2c8\ub2e4 \ud83d\ude42<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-white-color has-cyan-bluish-gray-background-color has-text-color has-background has-link-color wp-elements-790b4ede7486cf11fc8601a67c8dcb47\"> Personal Comments<\/h3>\n\n\n\n<p>\uc9c0\uae08\uae4c\uc9c0 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \ubc31\uc5c5 \uc5ec\ubd80\ub97c \ud6a8\uacfc\uc801\uc73c\ub85c \ubaa8\ub2c8\ud130\ub9c1\ud558\uace0 \uc54c\ub9bc\uc744 \ubc1b\uc744 \uc218 \uc788\ub294 \ubc29\ubc95\uc744 \uacf5\uc720\ud574\ubcf4\uc558\uc2b5\ub2c8\ub2e4. <\/p>\n\n\n\n<p>\ud558\uc9c0\ub9cc \uc6b0\ub9ac\ub294 \uc544\uc9c1 \uadfc\ubcf8\uc801\uc778 \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \ubc31\uc5c5 \uc5ec\ubd80\uc5d0 \ub300\ud55c \uc54c\ub9bc\uc744 \ubc1b\uc558\uc9c0\ub9cc \ubc31\uc5c5\uc774 \uc2e4\ud328\ud588\ub2e4\ub294 \uc0ac\uc2e4 \uc790\uccb4\ub294 \ub2ec\ub77c\uc9c0\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc785\ub2c8\ub2e4. \uc54c\ub9bc\uc740 \ubb38\uc81c\ub97c \uac10\uc9c0\ud558\ub294 \ub370\ub294 \ub3c4\uc6c0\uc774 \ub418\uc9c0\ub9cc \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uc9c0\ub294 \ubabb\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\ub2e4\uc74c \ud3ec\uc2a4\ud305\uc5d0\uc11c\ub294 \ud55c \uac78\uc74c \ub354 \ub098\uc544\uac00 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c \uc81c\uacf5\ud558\ub294 \uae30\ubcf8 \ubc31\uc5c5 \uae30\ub2a5\uc744 \uc0ac\uc6a9\ud558\uc9c0 \uc54a\uace0 \uc9c1\uc811 \ubc31\uc5c5\uc744 \uc790\ub3d9\ud654\ud558\uace0 \uc6d0\ud558\ub294 \uae30\uac04\ub9cc\ud07c \uc548\uc804\ud558\uac8c \ubcf4\uad00\ud560 \uc218 \uc788\ub294 \ubc29\ubc95\uc744 \uacf5\uc720\ub4dc\ub9ac\uaca0\uc2b5\ub2c8\ub2e4. <\/p>\n\n\n\n<p>\uae34 \uae00 \uc77d\uc5b4\uc8fc\uc154\uc11c \uac10\uc0ac\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"137\" src=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master.png\" alt=\"\" class=\"wp-image-1221\" srcset=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master.png 800w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master-300x51.png 300w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master-768x132.png 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\uc548\ub155\ud558\uc138\uc694 MANVSCLOUD \uae40\uc218\ud604\uc785\ub2c8\ub2e4. \ucd5c\uadfc \uc6b4\uc601\ud558\uace0 \uc788\ub294 Cloud DB for PostgreSQL\uc5d0\uc11c \uc9c0\uc18d\uc801\uc778 \ubc31\uc5c5 \uc2e4\ud328\uac00 \ubc1c\uc0dd\ud558\ub294 \ubb38\uc81c\uac00 \uc788\uc5c8\uc2b5\ub2c8\ub2e4. Cloud DB for PostgreSQL\uc740 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub85c \ubc31\uc5c5 \ubcf4\uad00\uc77c\uacfc \ubc31\uc5c5 \uc2dc\uac04\uc744 \uc124\uc815\ud560 \uc218 \uc788\ub294 \ud3b8\ub9ac\ud55c \uae30\ub2a5\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4. \ud558\uc9c0\ub9cc \uc124\uc815\ud55c \uc2dc\uac04\ub300\uc5d0 \ubc31\uc5c5\uc774 \uc81c\ub300\ub85c \uc774\ub8e8\uc5b4\uc9c0\uc9c0 \uc54a\uc544 1\uc77c 1\ubc31\uc5c5\uc774 \ub418\uc9c0 \uc54a\uace0 \uc694\uad6c\ub418\ub294 \ubc31\uc5c5 \ubcf4\uad00\uc77c\ub9cc\ud07c \ub370\uc774\ud130\uac00 \ubcf4\uad00\ub418\uc9c0 \uc54a\ub294 \ubb38\uc81c\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \ub370\uc774\ud130\ub294 \uc2dc\uc2a4\ud15c \uc6b4\uc601\uc5d0\uc11c \uac00\uc7a5 \uc911\uc694\ud55c \uc790\uc0b0 \uc911 \ud558\ub098\uc774\uba70 \ubc31\uc5c5\uc740 \uc774\ub97c \ubcf4\ud638\ud558\ub294 \ucd5c\ud6c4\uc758 \ubcf4\ub8e8\uc785\ub2c8\ub2e4. \ub530\ub77c\uc11c \uc624\ub298\uc740 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \ubc31\uc5c5\uc758 \uc131\uacf5\/\uc2e4\ud328 \uc5ec\ubd80\ub97c \ud6a8\uacfc\uc801\uc73c\ub85c \ubaa8\ub2c8\ud130\ub9c1\ud560 \uc218 \uc788\ub294 \uc54c\ub9bc \uae30\ub2a5\uc744 \uad6c\ud604\ud558\ub294 \ubc29\ubc95\uc744 \uacf5\uc720\ub4dc\ub9ac\uace0\uc790 \ud569\ub2c8\ub2e4. \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub3c4 \ubc31\uc5c5\uc5d0 \uc2e4\ud328\ud560 \uc218 \uc788\ub2e4 \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c\ub294 \uc704 \uc774\ubbf8\uc9c0\uc640 \uac19\uc774 \ubc31\uc5c5 \ubcf4\uad00\uc77c\uacfc \ubc31\uc5c5 \uc2dc\uac04\uc744 \uc9c0\uc815\ud574\uc904 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774\ub860\uc801\uc73c\ub85c\ub294 \ub9e4\uc77c \uc9c0\uc815\ud55c \uc2dc\uac04\ub300\uc5d0 \ubc31\uc5c5\uc774 \uc218\ud589\ub418\uba70 \uc124\uc815\ub41c \ubcf4\uad00\uc77c\ub9cc\ud07c \ubc31\uc5c5 \ub370\uc774\ud130\uac00 \uc548\uc804\ud558\uac8c \ubcf4\uad00\ub418\uc5b4\uc57c \ud569\ub2c8\ub2e4. (\uc120\uc0dd\ub2d8&#8230; \uc81c \ubc31\uc5c5\uc740 \uc5b4\ub514\ub85c \uac04 \uac83\uc785\ub2c8\uae4c? \ubc31\uc5c5 \uc2dc\uac04\uc740 \ubb34\uc2a8 \uc77c\uc774 \uc788\uc5c8\ub358 \uac81\ub2c8\uae4c?&#8230;) \ud558\uc9c0\ub9cc \uc5b4\ub290 \ub0a0 Backup \ub9ac\uc2a4\ud2b8\ub97c \ud655\uc778\ud574\ubcf4\ub2c8 \ubc31\uc5c5 \ub0a0\uc9dc\uac00 \ub744\uc5c4\ub744\uc5c4 \ub204\ub77d\ub418\uc5b4 \uc788\ub294 \ud604\uc0c1\uc744 \ubc1c\uacac\ud588\uc2b5\ub2c8\ub2e4. \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc6a9\ub7c9\uc774 \ub108\ubb34 \ucee4\uc11c \ubc31\uc5c5 \uc18c\uc694 \uc2dc\uac04\uc774 \uae38\uc5b4\uc838 \ub2e4\uc74c\ub0a0\ub85c \ubbf8\ub8e8\uc5b4\uc9c4 \uac83\ub3c4 \uc544\ub2c8\uc5c8\uc2b5\ub2c8\ub2e4. (5GB\ub3c4 \uc548\uc4f0\uace0 \uc788\ub2e4\uace0&#8230;) \uc6b0\uc120 \ud558\ub8e8\uc5d0 \ud55c \ubc88\uc529 \ubc31\uc5c5\uc774 \uc81c\ub300\ub85c \uc218\ud589\ub418\uc5c8\ub294\uc9c0 \ubaa8\ub2c8\ud130\ub9c1\uc774 \ub420 \ud544\uc694\uac00 \uc788\uc5c8\uc2b5\ub2c8\ub2e4. \uadf8\ub7ec\ub098 \ub9e4\ubc88 \ucf58\uc194\uc5d0 \uc811\uc18d\ud574\uc11c \ubc31\uc5c5 \uc0c1\ud0dc\ub97c \ud655\uc778\ud558\ub294 \uac83\uc740 \ub9e4\uc6b0 \ubc88\uac70\ub86d\uace0 \uc2dc\uac04 \uc18c\ubaa8\uc801\uc785\ub2c8\ub2e4. \uc800\ub294 \ub9e4\uc77c \uc544\uce68 \ucd9c\uadfc\uacfc \ub3d9\uc2dc\uc5d0 \ud544\uc694\ud55c \ud56d\ubaa9\ub4e4\uc744 \uc6b0\uc120\uc801\uc73c\ub85c \uccb4\ud06c\ud558\ub294 \ud3b8\uc785\ub2c8\ub2e4. \ub530\ub77c\uc11c \uad00\ub9ac\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \ubc31\uc5c5\ub3c4 \ub9e4\uc77c \uc544\uce68\ub9c8\ub2e4 \uc131\uacf5\uc801\uc73c\ub85c \uc218\ud589\ub418\uc5c8\ub294\uc9c0 Slack\uc73c\ub85c \uc54c\ub9bc\uc744 \ubc1b\uc544\ubcfc \uc218 \uc788\ub3c4\ub85d \ud588\uc2b5\ub2c8\ub2e4. \ubc31\uc5c5 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[505,1008,457,32,539,87,91,17,90,16,1010,805,1009,89,202,398,540,860,864],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts\/2988"}],"collection":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2988"}],"version-history":[{"count":3,"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts\/2988\/revisions"}],"predecessor-version":[{"id":2997,"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts\/2988\/revisions\/2997"}],"wp:attachment":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2988"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2988"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2988"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}