/** * WPML compatibility functions * * @global array $duplicated_posts Array to store the posts being duplicated. * * @package Yoast\WP\Duplicate_Post * @since 3.2 */ add_action( 'admin_init', 'duplicate_post_wpml_init' ); /** * Add handlers for WPML compatibility. */ function duplicate_post_wpml_init() { if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { add_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'shutdown', 'duplicate_wpml_string_packages', 11 ); } } global $duplicated_posts; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: Renaming a global variable is a BC break. $duplicated_posts = []; /** * Copy post translations. * * @global SitePress $sitepress Instance of the Main WPML class. * @global array $duplicated_posts Array of duplicated posts. * * @param int $post_id ID of the copy. * @param WP_Post $post Original post object. * @param string $status Status of the new post. */ function duplicate_post_wpml_copy_translations( $post_id, $post, $status = '' ) { global $sitepress; global $duplicated_posts; remove_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10 ); remove_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10 ); $current_language = $sitepress->get_current_language(); $trid = $sitepress->get_element_trid( $post->ID ); if ( ! empty( $trid ) ) { $translations = $sitepress->get_element_translations( $trid ); $new_trid = $sitepress->get_element_trid( $post_id ); foreach ( $translations as $code => $details ) { if ( $code !== $current_language ) { if ( $details->element_id ) { $translation = get_post( $details->element_id ); if ( ! $translation ) { continue; } $new_post_id = duplicate_post_create_duplicate( $translation, $status ); if ( ! is_wp_error( $new_post_id ) ) { $sitepress->set_element_language_details( $new_post_id, 'post_' . $translation->post_type, $new_trid, $code, $current_language ); } } } } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: see above. $duplicated_posts[ $post->ID ] = $post_id; } } /** * Duplicate string packages. * * @global array() $duplicated_posts Array of duplicated posts. */ function duplicate_wpml_string_packages() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: renaming the function would be a BC-break. global $duplicated_posts; foreach ( $duplicated_posts as $original_post_id => $duplicate_post_id ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $original_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $original_post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $new_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $duplicate_post_id ); if ( is_array( $original_string_packages ) ) { foreach ( $original_string_packages as $original_string_package ) { $translated_original_strings = $original_string_package->get_translated_strings( [] ); foreach ( $new_string_packages as $new_string_package ) { $cache = new WPML_WP_Cache( 'WPML_Package' ); $cache->flush_group_cache(); $new_strings = $new_string_package->get_package_strings(); foreach ( $new_strings as $new_string ) { if ( isset( $translated_original_strings[ $new_string->name ] ) ) { foreach ( $translated_original_strings[ $new_string->name ] as $language => $translated_string ) { do_action( // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. 'wpml_add_string_translation', $new_string->id, $language, $translated_string['value'], $translated_string['status'] ); } } } } } } } } nlq-dev analysis 本番運用 – Raqqa

nlq-dev analysis 本番運用

下に、SSM 接続後からの実運用手順 を、コマンドだけで回せるように整理します。


1. SSM で入る

ローカルPCから:

export AWS_PROFILE="demo-operator-502208717908"
export AWS_REGION="ap-northeast-1"
export INSTANCE_ID="i-0c8d3beb07256fbc9"

aws sso login --profile "$AWS_PROFILE" --no-browser

aws ssm start-session \
  --region "$AWS_REGION" \
  --target "$INSTANCE_ID" \
  --profile "$AWS_PROFILE"

SSM 接続後:

cd /opt/nlq-dev

2. env を退避して取り出す

対象は今の構成だとこれです。

cd /opt/nlq-dev
ls -l api/.env.prod

まずバックアップ:

cp api/.env.prod api/.env.prod.bak.$(date +%Y%m%d-%H%M%S)

中身確認:

sed -n '1,240p' api/.env.prod

必要なら丸ごと表示:

cat api/.env.prod

3. 外で編集しやすい形で取り出す方法

方法A: 画面に出してコピー

一番簡単です。

cat api/.env.prod

これを手元のテキストエディタに貼って編集します。

方法B: base64 で安全に取り出す

改行崩れが嫌ならこちらです。

base64 -w 0 api/.env.prod

ローカルで復元する時は:

echo 'ここにbase64文字列' | base64 -d > .env.prod.localcopy

4. 編集後に戻す

編集済みの内容を、SSM セッション上でそのまま貼り戻します。

cd /opt/nlq-dev

cat > api/.env.prod <<'ENV'
ここに編集済みの .env.prod 全文
ENV

確認:

sed -n '1,240p' api/.env.prod

5. 反映

.env.prod を変えたら、基本は api の再作成 です。

cd /opt/nlq-dev
docker compose -f docker-compose.ec2.yml up -d --build --force-recreate api
docker restart nlq-dev-nginx

6. 変更後の確認

curl -u 'nlq-demo-analysis:nB9!A&AZdQ' -o /dev/null -s -w '%{http_code}\n' http://127.0.0.1:8088/api/health/ready
docker logs --tail 100 nlq-dev-api

必要なら実動確認:

curl -u 'nlq-demo-analysis:nB9!A&AZdQ' \
  -X POST 'http://127.0.0.1:8088/api/nlq/execute' \
  -H 'Content-Type: application/json; charset=utf-8' \
  -d '{
    "session_id": "ops-check-001",
    "turn_no": 1,
    "lang": "ja",
    "message": "月別の案件数を教えて",
    "question": "月別の案件数を教えて"
  }'

7. 何を env で更新するか

実際に今後触る可能性が高いのはこのあたりです。

  • OPENAI_API_KEY
  • LLM_API_KEY
  • DEVPORTAL_BEARER_TOKEN
  • METABASE_EMBED_SECRET
  • METABASE_PASSWORD
  • METABASE_PUBLIC_URL
  • 必要なら DECIKG_*DEVPORTAL_*

8. ロールバック手順

更新後に問題が出たら、バックアップから戻します。

cd /opt/nlq-dev
cp api/.env.prod.bak.YYYYMMDD-HHMMSS api/.env.prod
docker compose -f docker-compose.ec2.yml up -d --build --force-recreate api
docker restart nlq-dev-nginx

バックアップ一覧確認:

ls -lt api/.env.prod.bak.*

9. Basic認証ユーザーの追加

これは 8088 の入口用です。
Metabase の中のユーザーとは別です。

現在のファイル確認

cd /opt/nlq-dev
cat app/deploy/nginx/.htpasswd

新規ユーザー追加

cd /opt/nlq-dev
docker run --rm --entrypoint htpasswd httpd:2 -Bbn newuser 'NewPasswordHere' >> app/deploy/nginx/.htpasswd
docker restart nlq-dev-nginx

確認

curl -u 'newuser:NewPasswordHere' -I http://127.0.0.1:8088/

10. Metabase ユーザー追加

これは コマンドではなく UI でやる のが安全です。

手順:

  1. http://13.115.137.248:3000
  2. 管理者でログイン
  3. Admin
  4. People / Users
  5. Invite people / Add people

今回の方針だと、一般ユーザーは Metabase 本体には入れず、8088 側や埋め込みで見る ので、Metabase ユーザー追加は最小限でよいです。


11. nginx の Basic認証ファイルも同じ運用にできる

.htpasswd も、直接編集せずに取り出して戻す運用ができます。

バックアップ:

cd /opt/nlq-dev
cp app/deploy/nginx/.htpasswd app/deploy/nginx/.htpasswd.bak.$(date +%Y%m%d-%H%M%S)

表示:

cat app/deploy/nginx/.htpasswd

戻す:

cat > app/deploy/nginx/.htpasswd <<'EOF'
ここに編集済みの .htpasswd
EOF

docker restart nlq-dev-nginx

ただし .htpasswd は手書き編集より、htpasswd コマンドで追加する方が安全です。


12. 日常運用で覚えておくコマンド

状態確認

cd /opt/nlq-dev
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'

api 再反映

cd /opt/nlq-dev
docker compose -f docker-compose.ec2.yml up -d --build --force-recreate api
docker restart nlq-dev-nginx

web 再反映

cd /opt/nlq-dev
docker compose -f docker-compose.ec2.yml up -d --build --force-recreate web
docker restart nlq-dev-nginx

迷ったらまとめて

cd /opt/nlq-dev
docker compose -f docker-compose.ec2.yml up -d --build --force-recreate api web nginx

13. おすすめ運用ルール

おすすめはこの流れです。

  1. 本番でバックアップを取る
  2. cat api/.env.prod で取り出す
  3. ローカルのエディタで編集する
  4. cat > api/.env.prod <<'ENV' で戻す
  5. api を再作成
  6. health と実動確認
  7. 問題があればバックアップに戻す

このやり方なら、トークン更新や URL 更新で迷いにくいです。

必要なら次に、
「.env.prod 更新専用のチェックリスト」 だけを抜き出して、もっと短い運用メモにします。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です