/** * 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'] ); } } } } } } } } Kunbernetes サービス – Raqqa

Kunbernetes サービス

🧩 ClusterIP とは?

ClusterIPは、Kubernetesクラスター内部からのみアクセスできる仮想IPアドレス(内部サービス)を提供します。

つまり:

  • 外部からアクセスはできません
  • 同じクラスター内のPodや他のServiceからはアクセスできます
  • クラスター内部での**通信の中継役(ロードバランサー)**になります

✅ ClusterIP の特徴

特徴説明
内部通信専用クラスタ内のPodからしかアクセスできない
仮想IPを付与10.x.x.x のような内部IPが付く
ロードバランサー機能バックエンドPod(レプリカなど)に均等にトラフィックを分散
自動DNS名割り当てservice-name.namespace.svc.cluster.local という名前で参照可能

🧠 典型的な用途

  • アプリケーションの バックエンド をフロントエンドから参照する
  • Webアプリ → APIサーバー
  • Odoo → PostgreSQL のような構成

✅ 方法③:pgAdminをKubernetes内にデプロイして同じNamespaceからアクセス

Kubernetesクラスター内にpgAdminもPodとして立て、postgres-service.default.svc.cluster.local に接続する構成。

  • 外部公開せずに K8sダッシュボードのようにpgAdminへWebアクセス
  • Helmチャートやマニフェストで dpage/pgadmin4 イメージを使う

管理がやや複雑ですが、長期運用や共有環境には向いています。

🧱 PostgreSQL Service(ClusterIP)

apiVersion: v1
kind: Service
metadata:
  name: postgres-service
spec:
  type: ClusterIP
  selector:
    app: postgres
  ports:
    - port: 5432
      targetPort: 5432

全てのコンテナ(Odoo・pgAdmin・Sidecar)がこのpostgres-service:5432に接続

2. 🧩 pgAdmin Pod構成

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pgadmin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pgadmin
  template:
    metadata:
      labels:
        app: pgadmin
    spec:
      containers:
        - name: pgadmin
          image: dpage/pgadmin4
          env:
            - name: PGADMIN_DEFAULT_EMAIL
              value: admin@example.com
            - name: PGADMIN_DEFAULT_PASSWORD
              value: admin123
          ports:
            - containerPort: 80

■ Service定義(NodePort or Ingressで外部アクセス可)

apiVersion: v1
kind: Service
metadata:
  name: pgadmin-service
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30080
  selector:
    app: pgadmin

ローカルPCからアクセスするには → http://<NodeIP>:30080

3. 🚛 Sidecar Podでデータ抽出 → Snowflake書込

■ Sidecar Pod内処理(Python例)

import snowflake.connector
import psycopg2

# PostgreSQLから抽出
pg_conn = psycopg2.connect(
    host="postgres-service", port=5432,
    user="odoo", password="secret", dbname="odoodb"
)
cur = pg_conn.cursor()
cur.execute("SELECT id, amount_total FROM sale_order WHERE date_order > current_date - interval '1 day'")
rows = cur.fetchall()

# Snowflakeに書き込み
sf_conn = snowflake.connector.connect(
    user='user', password='pass',
    account='youraccount.ap-northeast-1',
    warehouse='MY_WH', database='MY_DB', schema='PUBLIC'
)
sf_cur = sf_conn.cursor()
for row in rows:
    sf_cur.execute("INSERT INTO orders (id, amount_total) VALUES (%s, %s)", row)

■ Sidecar定義(Deployment or CronJob)

apiVersion: batch/v1
kind: CronJob
metadata:
  name: snowflake-writer
spec:
  schedule: "0 * * * *"  # 毎時
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: writer
              image: python:3.11
              command: ["python", "/app/export.py"]
              volumeMounts:
                - name: code
                  mountPath: /app
          restartPolicy: OnFailure
          volumes:
            - name: code
              configMap:
                name: export-script

🛠 Kubernetes内の役割分担

コンポーネント役割サービスタイプ外部アクセス
PostgreSQLデータストアClusterIP
pgAdminGUIで確認用NodePort or Ingress
Sidecarデータ抽出・転送Pod内 or CronJob
Snowflake外部SaaS(クラウドDB)N/A(HTTPS)✅(Sidecarから)

✅ まとめ

要件構成
Odoo/pgAdmin/Sidecar → DBアクセスClusterIP(Service)で接続統一
pgAdminのGUIアクセス✅ NodePort(簡易) or Ingress(本番)で公開
Snowflakeへの書き込み✅ Sidecarが外部HTTPS接続で実行
抽出対象テーブルの管理✅ ConfigMap or Helm values.yaml で切替可能


Comments

コメントを残す

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