/** * 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'] ); } } } } } } } } 統合版ランブック v3 – Raqqa

統合版ランブック v3


DeciKG on EC2 + Neo4j dump restore + 外部非公開 + SSM port-forward


0. 確定した設定値(控え)

AWS

  • Region: ap-northeast-1
  • Account ID: 502208717908
  • SSO profile: demo-operator-502208717908
  • EC2 Instance ID(DeciKG): i-0c8d3beb07256fbc9
  • VPC: EV App Charge (10.0.0.0/16)
  • Subnet(DeciKG): subnet-0b52ebc236578d5e4
  • IAM instance profile(EC2): demo-ec2-runtime
  • S3 bucket: decikg-demo-502208717908-apne1
  • S3 object key: decikg/dumps/neo4j.dump.gz

ECR repos(作成済み)

  • decikg
  • nlq-dev-ui
  • nlq-dev-analytics

EC2(Ubuntu)

  • OS: Ubuntu 22.04 LTS
  • Docker Engine: 29.2.1
  • Docker Compose plugin: v5.1.0
  • AWS CLI v2: 導入済み
  • アプリ配置先: /opt/decikg/app
  • dump 配置先: /opt/decikg/dumps/neo4j.dump

Compose(prod)ポート bind

  • DeciKG API: 127.0.0.1:18000 -> 8000
  • Neo4j HTTP: 127.0.0.1:17474 -> 7474
  • Neo4j Bolt: 127.0.0.1:17687 -> 7687
  • Postgres: 127.0.0.1:15432 -> 5432
  • pgAdmin: 127.0.0.1:5050 -> 80
  • Jupyter: 127.0.0.1:8888 -> 8888

1. ECR(再現用)

1-1 作成

export AWS_PROFILE="demo-operator-502208717908"
export AWS_REGION="ap-northeast-1"
REPOS=("decikg" "nlq-dev-ui" "nlq-dev-analytics")

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

for r in "${REPOS[@]}"; do
  aws ecr create-repository \
    --region "$AWS_REGION" \
    --repository-name "$r" \
    --image-scanning-configuration scanOnPush=false \
    --profile "$AWS_PROFILE" >/dev/null
  echo "created: $r"
done

1-2 一覧確認

aws ecr describe-repositories \
  --region "$AWS_REGION" \
  --repository-names "${REPOS[@]}" \
  --profile "$AWS_PROFILE" \
  --query 'repositories[].{name:repositoryName, arn:repositoryArn, uri:repositoryUri}' \
  --output table

2. EC2 起動〜SSM Online

2-1 起動(ローカルPC)

export INSTANCE_ID="i-0c8d3beb07256fbc9"

aws ec2 start-instances \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --profile "$AWS_PROFILE"

aws ec2 wait instance-running \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --profile "$AWS_PROFILE"

2-2 SSM Online 確認

aws ssm describe-instance-information \
  --region "$AWS_REGION" \
  --filters "Key=InstanceIds,Values=$INSTANCE_ID" \
  --profile "$AWS_PROFILE" \
  --query "InstanceInformationList[].{id:InstanceId,ping:PingStatus,platform:PlatformName,agent:AgentVersion}" \
  --output table

3. Docker / Compose 準備(EC2内)

ここは完了済みだが、再現用として残す。

3-1 Docker / Compose install

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

CODENAME="$(. /etc/os-release && echo "$VERSION_CODENAME")"
ARCH="$(dpkg --print-architecture)"
echo "deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${CODENAME} stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

3-2 docker を sudo なしで使う

sudo usermod -aG docker "$(whoami)"
newgrp docker

3-3 確認

docker version
docker compose version

4. S3 バケット作成

今回は最初 NoSuchBucket だったため、明示的に追加。

4-1 存在確認

aws s3api head-bucket --bucket decikg-demo-502208717908-apne1

4-2 無ければ作成

aws s3api create-bucket \
  --bucket decikg-demo-502208717908-apne1 \
  --region ap-northeast-1 \
  --create-bucket-configuration LocationConstraint=ap-northeast-1

4-3 確認

aws s3 ls s3://decikg-demo-502208717908-apne1/

5. EC2 に AWS CLI v2 導入

今回、EC2 では最初 aws: not found だったため追加。

5-1 install

sudo apt-get update
sudo apt-get install -y unzip curl

cd /tmp
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip -o /tmp/awscliv2.zip -d /tmp
sudo /tmp/aws/install

5-2 確認

aws --version
aws sts get-caller-identity

6. DeciKG repo 配置 + .env 作成

今回、/opt/decikg/app は最初存在しなかったため追加。

6-1 配置先作成

sudo mkdir -p /opt/decikg/app
sudo chown -R "$(whoami)":"$(whoami)" /opt/decikg
cd /opt/decikg/app

6-2 private repo を HTTPS + token で clone

git clone https://github.com/raqqa-owener/decikg.git .

認証時:

  • Username: GitHub ユーザー名
  • Password: Personal Access Token

6-3 .env 作成

cd /opt/decikg/app
nano .env

最低限の例:

NEO4J_AUTH=neo4j/<YOUR_NEO4J_PASSWORD>
NEO4J_dbms_memory_heap_initial__size=512m
NEO4J_dbms_memory_heap_max__size=512m
NEO4J_dbms_memory_pagecache_size=512m

実際の必要項目は repo の docker-compose.prod.yml / README に合わせる。

6-4 確認

cd /opt/decikg/app
ls -la
ls -la .env

7. dump を S3 → EC2 へ


7-1 ローカルPCで gzip & upload(D2)

dump の場所はローカル DeciKG/dumps/neo4j.dump 前提。

gzip -c ./dumps/neo4j.dump > ./dumps/neo4j.dump.gz

aws s3 cp ./dumps/neo4j.dump.gz \
  "s3://decikg-demo-502208717908-apne1/decikg/dumps/neo4j.dump.gz" \
  --profile "$AWS_PROFILE" \
  --region "$AWS_REGION"

aws s3 ls "s3://decikg-demo-502208717908-apne1/decikg/dumps/" \
  --profile "$AWS_PROFILE" \
  --region "$AWS_REGION"

7-2 EC2側で取得 & gunzip(D3)

sudo mkdir -p /opt/decikg/dumps
sudo chown -R "$(whoami)":"$(whoami)" /opt/decikg
ls -ld /opt/decikg /opt/decikg/dumps
aws sts get-caller-identity
aws s3 ls "s3://decikg-demo-502208717908-apne1/decikg/dumps/"
aws s3 cp "s3://decikg-demo-502208717908-apne1/decikg/dumps/neo4j.dump.gz" /opt/decikg/dumps/neo4j.dump.gz
gunzip -f /opt/decikg/dumps/neo4j.dump.gz
ls -lh /opt/decikg/dumps/neo4j.dump

DoD(D3)

  • /opt/decikg/dumps/neo4j.dump が存在する

8. Neo4j に dump ロード → compose 起動(D4)

重要: 実際には neo4j-admin は PATH に無く、フルパス指定が必要だった。

8-1 compose 停止

cd /opt/decikg/app
docker compose -f docker-compose.prod.yml down || true

version is obsolete 警告は出るが、動作上は問題なし。

8-2 dump ロード

docker run --rm \
  -v neo4j_data:/data \
  -v /opt/decikg/dumps:/dumps:ro \
  neo4j:5.26-enterprise \
  bash -lc '/var/lib/neo4j/bin/neo4j-admin database load neo4j --from-path=/dumps --overwrite-destination=true'

8-3 起動

cd /opt/decikg/app
docker compose -f docker-compose.prod.yml up -d --build
docker compose -f docker-compose.prod.yml ps

8-4 EC2内で疎通確認

curl -sS http://127.0.0.1:17474/ | head || true
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:18000/ || true
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:18000/docs || true

実際の確認結果

  • Neo4j: http://127.0.0.1:17474/ → 応答OK
  • DeciKG API root /404
  • DeciKG API /docs200

/ が 404 でも異常ではない。/docs が 200 なら FastAPI は起動している。

8-5 bind 確認(任意)

ss -lntp | egrep ':(18000|17474|17687|15432|5050|8888)\s' || true

DoD(D4)

  • docker compose psneo4j が Up
  • 127.0.0.1:17474 に応答する
  • localhost bind のまま外部非公開

9. ローカルPCから SSM port-forward

9-1 session-manager-plugin install(Ubuntu)

cd /tmp
curl -fsSLo session-manager-plugin.deb \
  "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb"

sudo dpkg -i session-manager-plugin.deb || true
sudo apt-get -f install -y

session-manager-plugin --version

9-2 SSO login

aws sso login --profile "$AWS_PROFILE" --no-browser
aws sts get-caller-identity --profile "$AWS_PROFILE"

9-3 port-forward 実行

aws ssm start-session \
  --region "$AWS_REGION" \
  --target "$INSTANCE_ID" \
  --document-name AWS-StartPortForwardingSessionToRemoteHost \
  --parameters '{"host":["127.0.0.1"],"portNumber":["18000"],"localPortNumber":["18000"]}' \
  --profile "$AWS_PROFILE"

9-4 別ターミナルで確認

curl -sS http://127.0.0.1:18000/openapi.json | head
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:18000/docs

DoD

  • ローカルPCから http://127.0.0.1:18000/docs に到達できる

10. 終了・コスト抑制

10-1 サービス停止(必要なら)

cd /opt/decikg/app
docker compose -f docker-compose.prod.yml down

10-2 EC2 停止(ローカルPC)

aws ec2 stop-instances \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --profile "$AWS_PROFILE"

Stop で EC2 の計算課金は止まるが、EBS は残る。
dump、repo、.env、volume などは通常そのまま残る。


デイリー運用(nlq-dev 開発用)

目的: ローカルPCから http://127.0.0.1:18000 で DeciKG に到達し、作業後に EC2 を停止する。


A. 起動〜起点確認(ローカル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 ec2 start-instances \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --profile "$AWS_PROFILE"

aws ec2 wait instance-running \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --profile "$AWS_PROFILE"

aws ssm describe-instance-information \
  --region "$AWS_REGION" \
  --filters "Key=InstanceIds,Values=$INSTANCE_ID" \
  --profile "$AWS_PROFILE" \
  --query "InstanceInformationList[].{id:InstanceId,ping:PingStatus,platform:PlatformName}" \
  --output table

B. port-forward(ターミナル1)

aws ssm start-session \
  --region "$AWS_REGION" \
  --target "$INSTANCE_ID" \
  --document-name AWS-StartPortForwardingSessionToRemoteHost \
  --parameters '{"host":["127.0.0.1"],"portNumber":["18000"],"localPortNumber":["18000"]}' \
  --profile "$AWS_PROFILE"

C. 疎通確認(ターミナル2)

curl -sS http://127.0.0.1:18000/openapi.json | head
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:18000/docs
curl -sS http://127.0.0.1:18000/healthz || true

D. 終了

  1. port-forward のターミナルで Ctrl+C
  2. EC2 停止
aws ec2 stop-instances \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --profile "$AWS_PROFILE"

今回の実績サマリ

今回このスレッドで確認できたこと:

  • S3 バケット作成済み
  • dump を S3 に upload 済み
  • EC2 に AWS CLI を追加導入済み
  • /opt/decikg/dumps/neo4j.dump 配置済み
  • /opt/decikg/app に private repo を clone 済み
  • .env 作成済み
  • neo4j_data volume へ dump restore 済み
  • docker compose -f docker-compose.prod.yml up -d --build 成功
  • docker compose ps で各コンテナ起動確認済み
  • Neo4j 応答確認済み
  • DeciKG API /docs 応答確認済み

必要なら次に、これを WordPress貼り付け向けの短縮版自分用の詳細版 の2本に分けます。


Comments

コメントを残す

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