13 分で読了 #devops #runbooks
このページの目次

wildwindstudio.com EdgeOne(EO)運用保守マニュアル

サイトゾーン:wildwindstudio.com = zone-31ojren22baa(腾讯云 EdgeOne、個人版 plan-personal、DNSPodAccess 接続、DNS レコードは DNSPod に格納) 以下の2つの操作をカバー:① バックエンド API ドメインを EO に逆プロキシする ② フロントエンドの静的サイトを COS バケット + EO でホスティングする


0. 認証情報のマップ(機密情報マスキング済み)

認証情報用途値の保存場所
メインアカウントキー(appid 1258895932、ラベル tencent_sms)EO / DNSPod / COS / CAM の管理。本マニュアルの全管理操作でこれを使用プロジェクト resflow/config.toml[tencent_sms](DB への格納禁止)
tencent_email キー別のアカウント(appid 1392608203)、⁠本ゾーンとは無関係同上 [tencent_email]
フロントエンドアップロード認証情報CAM サブユーザー cos_op(Uin 100049168554)、フロントエンドの coscli アップロード + EO キャッシュパージフロントエンド側で保持;ポリシーは §4 を参照
CLB _origin 証明書(certbot)EO→CLB への origin 接続部分の証明書bj-middleware-1、別マニュアル《wildwindstudio.com 証明書の自動更新》を参照

⚠️ tccli で teo の書き込み操作を行う際は、必ず --endpoint teo.tencentcloudapi.com を指定すること。指定しない場合、デフォルトで国際サイトの teo.intl.tencentcloudapi.com に解決され、接続タイムアウトが発生する。 ⚠️ tccli には cos サービス がなく、マシン上に coscli/SDK も存在しない;COS 操作は手書きの HMAC-SHA1 署名 + python requests による XML API 直接呼び出しを行う(スクリプトは §5 を参照)。

管理認証情報を環境変数に設定する(以降のコマンドは export 済みと仮定する):

# config.toml の [tencent_sms] から読み取り、プレーンテキストでの貼り付けを避ける
cd <resflow プロジェクトディレクトリ>
eval "$(python3 - <<'PY'
import re
t=open('config.toml').read()
m=re.search(r'\[tencent_sms\](.*?)(\n\[|\Z)', t, re.S).group(1)
sid=re.search(r'secret_id\s*=\s*"([^"]+)"',m).group(1)
sk=re.search(r'secret_key\s*=\s*"([^"]+)"',m).group(1)
print(f'export TENCENTCLOUD_SECRET_ID={sid}; export TENCENTCLOUD_SECRET_KEY={sk}')
PY
)"

1. シナリオ A:バックエンド API ドメインを EO に逆プロキシする

cn-reserve-api.wildwindstudio.com を例とする(腾讯云 CLB への origin 接続)。

シナリオ A: API 逆プロキシリクエストチェーン クライアント HTTPS EO エッジ TLS 終端 · CC/WAF 基本保護 origin HTTPS:443 HostHeader 透過で元ドメインを伝播 CLB lb-mm70ra69 443 リスナー · L7 ホストルール k8s 2段階のHTTPS:クライアント→EO エッジで証明書終端、EO→CLB への origin 接続も HTTPS:443(origin 証明書は certbot で自動更新)、 HostHeader 透過により CLB がドメインに応じて k8s へ転送;新しいホストに個別ポリシーがない場合、デフォルトでサイトレベルの ZoneDefaultPolicy 保護にフォールバック。

手順⁠(順序:まず origin 接続と証明書の作成、証明書がデプロイされた後に DNS を切り替えて、5xx の空白期間を避ける):

ZONE=zone-31ojren22baa
DOMAIN=cn-reserve-api.wildwindstudio.com
CLB=lb-mm70ra69-ihl1vfoqucp93sma.clb.bj-tencentclb.com

# ① 加速ドメインの作成(IP_DOMAIN へ origin 接続、HTTPS:443 を強制;CLB の 80 は強制 302 リダイレクトなので、80 へは origin 接続しない)
tccli teo CreateAccelerationDomain --region ap-guangzhou --endpoint teo.tencentcloudapi.com \
  --ZoneId $ZONE --DomainName $DOMAIN \
  --OriginInfo '{"OriginType":"IP_DOMAIN","Origin":"'$CLB'","PrivateAccess":"off"}' \
  --OriginProtocol HTTPS --HttpsOriginPort 443
# 戻り値 OwnershipVerification=null は所有権検証が不要(サブドメインはゾーンから継承)

# ② エッジ無料証明書の有効化(EO が自動発行 + 自動更新)
tccli teo ModifyHostsCertificate --region ap-guangzhou --endpoint teo.tencentcloudapi.com \
  --ZoneId $ZONE --Hosts '["'$DOMAIN'"]' --Mode eofreecert

# certStatus=deployed になるまでポーリング(約 4〜10 分)
tccli teo DescribeAccelerationDomains --region ap-guangzhou --endpoint teo.tencentcloudapi.com \
  --ZoneId $ZONE | python3 -c "import json,sys;d=json.load(sys.stdin);[print(a['DomainStatus'],(a.get('Certificate') or {}).get('List',[{}])[0].get('Status')) for a in d['AccelerationDomains'] if a['DomainName']=='$DOMAIN']"

# ③ 証明書が deployed になったら、DNSPod の該当レコードを EO エントリポイント <domain>.eo.dnse1.com へ変更
#    —— RecordId を取得し、ModifyRecord で(この1レコードのみ)更新
tccli dnspod DescribeRecordList --endpoint dnspod.tencentcloudapi.com \
  --Domain wildwindstudio.com --Subdomain cn-reserve-api           # RecordId を取得
tccli dnspod ModifyRecord --endpoint dnspod.tencentcloudapi.com \
  --Domain wildwindstudio.com --RecordId <RECORD_ID> \
  --SubDomain cn-reserve-api --RecordType CNAME --RecordLine 通常 \
  --Value cn-reserve-api.wildwindstudio.com.eo.dnse1.com --TTL 600

検証⁠(DNS 切り替え前に EO エッジ IP で事前チェック可能):

IP=$(dig +short @119.29.29.29 cn-reserve-api.wildwindstudio.com.eo.dnse1.com A | grep -E '^[0-9]' | head -1)
curl -s -o /dev/null -w "HTTP %{http_code} TLS %{ssl_verify_result}\n" \
  --resolve cn-reserve-api.wildwindstudio.com:443:$IP https://cn-reserve-api.wildwindstudio.com/openapi

保護⁠:新しいホストに個別ドメインレベルのポリシーがない場合、サイトレベルの ZoneDefaultPolicy にフォールバックする(CC 適応的レート制限 on/Loose/Challenge + 管理型 WAF on/DetectionOnly)。これは基本保護であり、きめ細かいレート制限は未設定。確認: tccli teo DescribeSecurityPolicy ... --Entity ZoneDefaultPolicy

注意:CC アクションは JSChallenge であるため、ブラウザ以外のクライアント(ゲームクライアントが API に直接接続するなど)でトリガーされると、チャレンジを解除できません;Loose モードでは極端な異常時のみトリガーされるため、許容範囲内です。


2. シナリオ B:COS 静的フロントエンド + EO ホスティング

cn-reservation.wildwindstudio.com を例とする。バケット cn-reservation-webui-1258895932(ap-nanjing)。バケット game-reserve-webui-1258895932(ap-tokyo、予約サイト)を参照。

シナリオ B: COS 静的フロントエンドリクエストチェーン クライアント HTTPS EO エッジ origin (FOLLOW) COS 静的ウェブサイトエンドポイント <bucket>.cos-website.<region>.myqcloud.com OriginProtocol=FOLLOW、COS 静的ウェブサイトエンドポイント(bucket-website ドメイン)へ origin 接続;シナリオ A とは異なり、 COS origin は HostHeader を送信できないため、EO が自動で設定します。手動で指定するとエラーになります。

手順⁠:

# ① バケット作成(読み取り公開)+ ② 静的ウェブサイト有効化(index.html + AutoAddressing)
#    —— §5 の cos_admin.py(手書き署名)またはコンソール操作を使用
python3 cos_admin.py create-bucket cn-reservation-webui-1258895932 ap-nanjing

# ③ EO に加速ドメインを作成(COS へ origin 接続;OriginType=COS の場合、【HostHeader】は渡せない、EO が自動設定)
ZONE=zone-31ojren22baa
WEP=cn-reservation-webui-1258895932.cos-website.ap-nanjing.myqcloud.com
tccli teo CreateAccelerationDomain --region ap-guangzhou --endpoint teo.tencentcloudapi.com \
  --ZoneId $ZONE --DomainName cn-reservation.wildwindstudio.com \
  --OriginInfo '{"OriginType":"COS","Origin":"'$WEP'","PrivateAccess":"off"}' \
  --OriginProtocol FOLLOW --HttpOriginPort 80 --HttpsOriginPort 443

# ④ エッジ証明書の有効化(シナリオ A ② と同様)
tccli teo ModifyHostsCertificate --region ap-guangzhou --endpoint teo.tencentcloudapi.com \
  --ZoneId $ZONE --Hosts '["cn-reservation.wildwindstudio.com"]' --Mode eofreecert

# ⑤ DNS:新しいサブドメインは CreateRecord を使用(既存レコードは変更しない)
tccli dnspod CreateRecord --endpoint dnspod.tencentcloudapi.com \
  --Domain wildwindstudio.com --SubDomain cn-reservation \
  --RecordType CNAME --RecordLine 通常 \
  --Value cn-reservation.wildwindstudio.com.eo.dnse1.com --TTL 600

検証⁠(空バケットへの origin 接続は COS 404 を返すはずで、リンクが通っていることを証明;index.html を配置すれば 200 になる):

DOM=cn-reservation.wildwindstudio.com
IP=$(dig +short @119.29.29.29 $DOM A | grep -E '^[0-9]' | head -1)
echo | openssl s_client -connect $IP:443 -servername $DOM 2>/dev/null | openssl x509 -noout -subject
# subject=CN=<ドメイン> ならエッジ証明書が展開済み(展開前だと *.cdn.myqcloud.com のデフォルト証明書になり、TLS 接続が失敗する)
curl -s -o /dev/null -w "HTTP %{http_code}\n" --resolve $DOM:443:$IP https://$DOM/

3. フロントエンドデプロイ(coscli アップロード + EO キャッシュパージ)

フロントエンドの2点セット(各サイトごとに1セット、バケット名 / パージ対象ドメインを変更するだけで対応可能):

coscli 設定⁠(cn-reservation-coscli.yaml):

cos:
  base:
    secretid: <cos_op の SecretId、マスキング済み>
    secretkey: <cos_op の SecretKey、マスキング済み>
    sessiontoken: ""
    protocol: https
  buckets:
  - name: cn-reservation-webui-1258895932     # 新しいバケットへ変更
    alias: website
    region: ap-nanjing                          # リージョンを変更
    endpoint: cos.ap-nanjing.myqcloud.com       # エンドポイントを変更
    ofs: false

キャッシュパージスクリプト⁠(TC3 署名で teo CreatePurgeTask を呼び出し、新しいサイトへの変更は Targets ドメインのみ変更すればよい):

export TENCENTCLOUD_SECRET_ID=<cos_op SecretId>
export TENCENTCLOUD_SECRET_KEY=<cos_op SecretKey>
# payload の Targets を対象ドメインへ変更:
# {"ZoneId":"*","Type":"purge_host","Targets":["cn-reservation.wildwindstudio.com"]}
./cn-reservation-purge.sh

公開フロー:coscli sync <ビルド成果物ディレクトリ> cos://website/ -c cn-reservation-coscli.yaml → パージスクリプトを実行。


4. フロントエンドアップロード認証情報の CAM 権限付与(新しいバケットで必須)

フロントエンドサブユーザー cos_op の権限は、単一のユーザー定義ポリシー cos_full_permission(PolicyId 274095472)によって制御される。 新しいバケットを追加するたびに、このポリシーの cos:* ステートメントに新しいバケットリソースを追加する必要がある。そうしないと、coscli アップロード時に 403 AccessDenied が発生する。 (teo:CreatePurgeTask* に権限が付与されており、任意のドメインのパージには追加操作は不要。)

# 現在ポリシーの読み取り
tccli cam GetPolicy --PolicyId 274095472

# 更新(既存バケットリソースを保持し、新しいバケットリソースを追加;resource 形式 qcs::cos:<region>:uid/<appid>:<bucket-appid>/*)
tccli cam UpdatePolicy --PolicyId 274095472 --PolicyDocument '{
  "version":"2.0",
  "statement":[
    {"action":["cos:*"],"effect":"allow","resource":[
      "qcs::cos:ap-tokyo:uid/1258895932:game-reserve-webui-1258895932/*",
      "qcs::cos:ap-nanjing:uid/1258895932:cn-reservation-webui-1258895932/*"
    ]},
    {"action":["teo:CreatePurgeTask"],"effect":"allow","resource":["*"]}
  ]
}'

サブユーザーの特定:cam ListUsers → 候補 cam ListAccessKeys --TargetUin <uin> で AK と一致 → cam ListAttachedUserPolicies --TargetUin <uin> でポリシーを検索。


5. 付録:COS 管理スクリプト(手書き署名、coscli 不要)

マシン上に coscli/SDK がない場合、python requests + COS HMAC-SHA1 署名で XML API を直接呼び出す。核心となる署名関数:

import time, hmac, hashlib, requests
def cos_sign(SID, SKEY, method, host, uri='/', headers=None, params=None):
    headers=headers or {'host':host}; params=params or {}
    now=int(time.time()); kt=f"{now};{now+600}"
    sk=hmac.new(SKEY.encode(),kt.encode(),hashlib.sha1).hexdigest()
    hl=';'.join(sorted(k.lower() for k in headers)); pl=';'.join(sorted(k.lower() for k in params))
    enc=lambda d:'&'.join(f"{k.lower()}={requests.utils.quote(str(d[k]),safe='')}" for k in sorted(d,key=str.lower))
    fmt=f"{method.lower()}\n{uri}\n{enc(params)}\n{enc(headers)}\n"
    sts=f"sha1\n{kt}\n{hashlib.sha1(fmt.encode()).hexdigest()}\n"
    sig=hmac.new(sk.encode(),sts.encode(),hashlib.sha1).hexdigest()
    return (f"q-sign-algorithm=sha1&q-ak={SID}&q-sign-time={kt}&q-key-time={kt}"
            f"&q-header-list={hl}&q-url-param-list={pl}&q-signature={sig}")
  • GET Service(全バケット一覧):host service.cos.myqcloud.com、GET /
  • PUT Bucket + 読み取り公開⁠:host <bucket>.cos.<region>.myqcloud.com、PUT /、署名時に x-cos-acl: public-read を併記
  • PUT 静的ウェブサイト⁠:PUT /?website、body は以下参照、content-md5(base64(md5(body)))+ content-type: application/xml が必要
  • 検証⁠:GET /?acl、GET /?website

静的ウェブサイトの body(参照バケットと同一):

<WebsiteConfiguration>
  <IndexDocument><Suffix>index.html</Suffix></IndexDocument>
  <AutoAddressing><Status>Enabled</Status></AutoAddressing>
</WebsiteConfiguration>

6. よくあるトラブルシューティング

現象原因 / 対処
teo.intl... timed outtccli teo の書き込み操作で --endpoint teo.tencentcloudapi.com を指定していない
UnSupportChangeHostHeaderWithThisOriginTypeOriginType=COS の場合、HostHeader を渡せないため、削除すること(EO が自動設定)
DNS 切り替え後、TLS 接続失敗、HTTP 000エッジ証明書が展開されていない。エッジ側で *.cdn.myqcloud.com をデフォルトで提供している;certStatus=deployed かつエッジの subject が自ドメインになるまで待つ(数分〜数十分)
coscli アップロードで 403 AccessDeniedcos_op ポリシーに該当バケットリソースが追加されていない、§4 を参照
DomainStatus が長時間 processEO 加速ドメインのプロビジョニング中。デプロイ済みの証明書機能には影響しない;自動的に online に切り替わる
DescribeDnsRecords(teo) が 0 件を返すdnsPodAccess モードでは DNS レコードは DNSPod にあるため、dnspod DescribeRecordList で確認すること

付録:本ゾーン既存の加速ドメイン

ドメインorigin 接続先用途
cn-reserve-api.wildwindstudio.comCLB lb-mm70ra69(HTTPS:443)中国国内用バックエンド API
cn-reservation.wildwindstudio.comCOS cn-reservation-webui(ap-nanjing)中国国内用予約フロントエンド
reservation / meltdown / wwwCOS 静的バケット日本国内用/公式サイトフロントエンド