[Docker, WLS, Kubernetes, Java] WebLogic Server JTA in a Kubernetes Environment

原文はこちら。
https://blogs.oracle.com/weblogicserver/weblogic-server-jta-in-a-kubernetes-environment

このエントリでは、Kubernetes環境で実行しているWebLogic Serverのグローバルトランザクションについて説明します。まず、WebLogic Server Transaction Manager(TM)が分散トランザクションをどのように処理するかを見ていきます。続いて、WebLogic Kubernetes Operatorを使用して、Kubernetesクラスタで実行されているWebLogic Serverドメインにデプロイされているトランザクションアプリケーションのサンプルを見ていきます。

WebLogic Server Transaction Manager

Introduction

WebLogic Server Transaction Manager (TM) はWebLogic Serverのトランザクション処理の監視実装で、Java Enterprise Edition(Java EE)のJava Transaction API(JTA)をサポートしています。Java EE applicationはJTAを使いグローバルトランザクションを管理して、データベースやメッセージングシステムといったリソースマネージャへの変更がユニットとして完成するか、もしくはその変更を元に戻すかを保証します。

このセクションでは、WebLogic Server Transaction Managerの概要を説明します。具体的には、ネットワーク通信と関連するコンフィグレーションに関する部分で、Kubernetes環境でのトランザクションを調べる際に役立ちます。このエントリでは扱わない多くのTransaction Managerの機能、最適化、および設定オプションがありますので、追加の詳細については、以下のWebLogic Serverドキュメントを参照してください。

How Transactions are Processed in WebLogic Server

WebLogic Server Transaction Managerがトランザクションをどのように処理するかについての基本的な理解を得るために、トランザクションを開始し、データベース表にレコードを挿入し、Java Messaging Service(JMS)キューの宛先にメッセージを送信するというServletで構成されるWebアプリケーションを考えます。JDBCおよびJMSリソースを更新した後、サーブレットはトランザクションをコミットします。下図は、サーバーおよびリソースのトランザクション参加者を示しています。

Transaction Propagation(トランザクションの伝播)
トランザクションコンテキストは、サーバー間およびアプリケーションがリソースにアクセスするときに状態を構築します。このアプリケーションでは、コミット時のトランザクションコンテキストは次のようになります。

ドメイン名とサーバー名で識別されるサーバー参加者には、Transaction Managerとの内部通信に使用される関連URLがあります。これらのURLは通常、サーバーのデフォルトネットワークチャネルまたはデフォルトのセキュアネットワークチャネルから取得されます。

トランザクション・コンテキストには、javax.transaction.Synchronizationコールバックを登録したサーバー参加者に関する情報も含まれています。JTA Synchronization APIは、トランザクションの2フェーズコミット処理を開始する前に、Transaction ManagerがSynchronization.beforeCompletion()メソッドを呼び出すコールバックメカニズムです。トランザクションの最終ステータス(例えばコミット、ロールバックなど)を伴ってトランザクションの処理が完了した後で、Synchronization.afterCompletion(int status)メソッドを呼び出します。

Transaction Completion
トランザクションをコミットするように指示されたTransaction Managerは、トランザクションの完了を調整します。サーバー参加者の1つを、2フェーズコミットプロトコルを駆動するためのトランザクション・コーディネータとして選択します。トランザクション・コーディネータは、残りの従属サーバーに、登録済みの同期コールバックの処理と、リソースの準備(prepare)、コミット、またはロールバックを指示します。下図では、トランザクションの例を調整するために使われるTransaction Managerとの通信チャネルを説明しています。

破線の矢印は、トランザクション・コーディネータと従属サーバ間の非同期RMI呼び出しを表します。Synchronization.beforeCompletion()の通信は、従属サーバー間で直接行うことができる点にご注意ください。Transaction Managerは、トランザクションを伝播するためにアプリケーションが使用しなかったネットワークチャネルを確立する可能性があるため、アプリケーション通信がTransaction Managerの内部通信と概念的に分離されていることも重要です。Transaction Managerは、サーバーのデフォルトネットワークチャネルの構成方法に応じて、異なるプロトコル、アドレス、およびポートを使用できます。

Configuration Recommendations

サーバーネットワークアドレス、永続ストレージ、サーバー命名規則に関連するTransaction Managerの推奨事項があります。

Server Network Addresses
前述のように、サーバー参加者は、トランザクション・コンテキストに含まれているURLを使用して相互に探索します。Transaction ManagerのURLに使用されるネットワークチャネルは、IPアドレスが変更される可能性があるノード、Pod、またはコンテナの再起動後に解決可能なアドレス名で構成することが重要です。また、Transaction Managerは直接のサーバー間通信を必要とするため、複数のIPアドレスに解決されるクラスタまたはロードバランサのアドレスは使用しないでください。

Transaction Logs
コーディネート・サーバーは、障害後のトランザクション・リカバリー処理に使用されるトランザクション・ログ(TLOG)に状態を保持します。サーバー・インスタンスが別のノードに再配置される可能性があるため、TLOGはNetwork File SystemやReplicated File System(NFS、SANなど)またはOracle RACなどの高可用性データベースに存在する必要があります。追加情報については、以下のドキュメントをご覧ください。
Oracle® Fusion Middleware高可用性ガイド 12c (12.2.1.3.0)
JMSおよびJTAの高可用性
https://docs.oracle.com/cd/E92951_01/lcm/ASHIA/GUID-C4750828-F83A-442A-8BFE-EE2F2D3945EE.htm#GUID-C4750828-F83A-442A-8BFE-EE2F2D3945EE
Oracle® Fusion Middleware High Availability Guide 12c (12.2.1.3.0)
JMS and JTA High Availability
https://docs.oracle.com/en/middleware/lifecycle/12.2.1.3/ashia/jms-and-jta-high-availability.html
Cross-Domain Transactions
WebLogic Serverドメインをまたがるトランザクションは、クロスドメイン・トランザクションと呼ばれます。クロスドメイン・トランザクションでは、特にドメインがパブリックネットワークで接続されている場合に、追加の構成要件が導入されます。

Server Naming
Transaction Managerは、ドメイン名とサーバー名の組み合わせを使用してサーバー参加者を識別します。 したがって、名前の衝突を防ぐために、各ドメインの名前を一意にする必要があります。 サーバー参加者名が衝突すると、実行時にトランザクションがロールバックされます。

Security
パブリックネットワークで接続されているサーバー参加者は、セキュアなプロトコル(例:t3s)と認証チェックを使用して、Transaction Manager通信が正当なものであることを確認する必要があります。 このデモではこれらのトピックについて詳しく説明しませんが、Kubernetesのサンプルアプリケーションでは、すべてのTransaction Manager通信はプライベートKubernetesネットワーク上で行われ、非SSLプロトコルを使用します。

クロスドメイン・トランザクションのセキュリティ設定の詳細は、以下のドキュメントをご覧ください。
Oracle® Fusion Middleware Oracle WebLogic Server JTAアプリケーションの開発 12c (12.2.1.3.0)
ドメイン間およびドメイン内トランザクションのセキュアな通信の構成
https://docs.oracle.com/cd/E92951_01/wls/WLJTA/trxsecurity.htm
Oracle® Fusion Middleware Developing JTA Applications for Oracle WebLogic Server 12c (12.2.1.3.0)
Configuring Secure Inter-Domain and Intra-Domain Transaction Communication
https://docs.oracle.com/middleware/12213/wls/WLJTA/trxsecurity.htm

WebLogic Server on Kubernetes

KubernetesとのWebLogic Serverの統合を改善するため、オープンソースのWebLogic Kubernetes OperatorをOracleはリリースしました。WebLogic Kubernetes Operatorは、WebLogic Serverドメインの作成と管理、さまざまなロードバランサとの統合、および追加機能をサポートしています。詳細については、GitHubプロジェクトページと、関連するブログを参照してください。
Oracle Weblogic Server Kubernetes Operator
https://github.com/oracle/weblogic-kubernetes-operator
How to... WebLogic Server on Kubernetes
https://blogs.oracle.com/weblogicserver/how-to-weblogic-server-on-kubernetes
https://orablogs-jp.blogspot.com/2018/01/how-to-weblogic-server-on-kubernetes.html

Example Transactional Application Walkthrough

Kubernetesで分散トランザクションを実行する方法を説明するために、単一のKubernetesクラスタ内で動作し、複数のWebLogic Serverドメインにデプロイされている、単純なトランザクションアプリケーションを考えます。この例で使用した環境は、Kubernetes v1.9.6を含むDocker Edge v18.05.0-ceを実行しているMacです。

Docker Edgeをインストールして起動後、Preferencesページを開き、[Advanced]タブでDockerで使用可能なメモリを増やし(〜8 GB)、[Kubernetes]タブでKubernetesを有効にします。変更を適用すると、DockerとKubernetesが開始します。ファイアウォールの内側にいる場合は、[Proxy]タブで適切な設定を追加する必要があります。実行すると、Kubernetesのバージョン情報を表示できます。
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.6", GitCommit:"9f8ebd171479bec0ada837d7ee641dec2f8c6dd1", GitTreeState:"clean", BuildDate:"2018-03-21T15:21:50Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.6", GitCommit:"9f8ebd171479bec0ada837d7ee641dec2f8c6dd1", GitTreeState:"clean", BuildDate:"2018-03-21T15:13:31Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
サンプルファイルのシステムのパス名を短縮するため、入力ファイル、Operatorのソースとバイナリ、永続ボリュームなどの作業ディレクトリは$HOME/k8sopの下に作成します。環境変数$K8SOPを使用してディレクトリを参照できます。
$ export K8SOP=$HOME/k8sop
$ mkdir $K8SOP

Install the WebLogic Kubernetes Operator

続いて、weblogic-kubernetes-operatorイメージをビルドしてインストールします。以下の手順を参照してインストールします。
WebLogic Server Kubernetes Operator - Installation
https://github.com/oracle/weblogic-kubernetes-operator/blob/master/site/installation.md
この例では、weblogic-kubernetes-operator GitHubプロジェクトが$K8SOP/srcディレクトリ($K8SOP/src/weblogic-kubernetes-operator)の下に複製されます。また、Dockerイメージを構築するときは、インストールドキュメントで指定されているsome-tagの代わりにlocalタグを使用してください。
$ mkdir $K8SOP/src
$ cd $K8SOP/src
$ git clone <a href="https://github.com/oracle/weblogic-kubernetes-operator.git">https://github.com/oracle/weblogic-kubernetes-operator.git</a>
$ cd weblogic-kubernetes-operator
$ mvn clean install
$ docker login
$ docker build -t weblogic-kubernetes-operator:local --no-cache=true .
Operatorイメージのビルド後、ローカルレジストリで以下の内容を確認できるはずです。
$ docker images weblogic-kubernetes-operator
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
weblogic-kubernetes-operator   local               42a5f70c7287        10 seconds ago      317MB
続いて、OperatorをKubernetesクラスターにデプロイします。この例では、create-weblogic-operator-inputs.yamlファイルを変更し、追加のターゲット名前空間(weblogic)を追加し、正しいOperatorイメージ名を指定します。


AttributeValue
targetNamespacesdefault,weblogic
weblogicOperatorImageweblogic-kubernetes-operator:local
javaLoggingLevelWARNING

修正した入力ファイルを$K8SOP/create-weblogic-operator-inputs.yamlに保存します。

次に、create-weblogic-operator.shスクリプトを実行して、変更したcreate-weblogic-operator.yaml入力ファイルへのパスとOperatorの出力ディレクトリのパスを指定します。
create-weblogic-operator.shスクリプトを実行して、変更したcreate-weblogic-operator.yaml入力ファイルへのパスとOperatorの出力ディレクトリのパスを指定します。
$ cd $K8SOP
$ mkdir weblogic-kubernetes-operator
$ $K8SOP/src/weblogic-kubernetes-operator/kubernetes/create-weblogic-operator.sh -i $K8SOP/create-weblogic-operator-inputs.yaml -o $K8SOP/weblogic-kubernetes-operator
スクリプト完了後、以下のようにOperator Podが実行中であると確認できるでしょう。
$ kubectl get po -n weblogic-operator
NAME                                 READY     STATUS    RESTARTS   AGE
weblogic-operator-6dbf8bf9c9-prhwd   1/1       Running   0          44s

WebLogic Domain Creation

WebLogic Serverドメインを作成する手順は、以下のURLに記載されています。
Creating a WebLogic domain
https://github.com/oracle/weblogic-kubernetes-operator/blob/master/site/creating-domain.md
WebLogic Serverドメインを作成する手順は、以下のURLに記載されています。
手順に従い、WebLogic ServerのDockerイメージをDocker StoreからローカルレジストリにPullします。Docker Storeで使用許諾契約書に同意した後、DockerイメージをPullできます。
$ docker login
$ docker pull store/oracle/weblogic:12.2.1.3
ドメイン管理者の資格情報(weblogic/weblogic1)を保持するKubernetesシークレットを作成します。
$ kubectl -n weblogic create secret generic domain1-weblogic-credentials --from-literal=username=weblogic --from-literal=password=weblogic1
このドメイン用の永続ボリュームの場所は$K8SOP/volumes/domain1とします。
$ mkdir -m 777 -p $K8SOP/volumes/domain1
次に、$K8SOP/src/weblogic-kubernetes-operator/kubernetes/create-weblogic-domain-inputs.yamlというサンプル入力ファイルをカスタマイズし、以下の属性を変更します。
AttributeValue
weblogicDomainStoragePath{full path of $HOME}/k8sop/volumes/domain1
domainNamedomain1
domainUIDdomain1
t3PublicAddress{your-local-hostname}
exposeAdminT3Channeltrue
exposeAdminNodePorttrue
namespaceweblogic
$ $K8SOP/src/weblogic-kubernetes-operator/kubernetes/create-weblogic-domain.sh -i $K8SOP/create-domain1.yaml -o $K8SOP/weblogic-kubernetes-operator
create-weblogic-domain.shスクリプトが完了すると、Kubernetesは管理サーバとクラスタ化された管理対象サーバインスタンスを起動します。しばらくすると、実行中のPodを確認できます。
$ kubectl get po -n weblogic
NAME                                        READY     STATUS    RESTARTS   AGE
domain1-admin-server                        1/1       Running   0          5m
domain1-cluster-1-traefik-9985d9594-gw2jr   1/1       Running   0          5m
domain1-managed-server1                     1/1       Running   0          3m
domain1-managed-server2                     1/1       Running   0          3m
WebLogic Server管理コンソールを使って、実行中の管理サーバにアクセスし、ドメインの状態を確認します(http://localhost:30701/console、資格証明はweblogic/weblogic1)。 下図は[サーバー]のページです。

管理コンソールの[サーバー]ページでは、domain1のすべてのサーバが表示されます。各サーバには、特定のサーバ・インスタンスに対して定義されたKubernetesサービス名に対応するリスンアドレスがあります。サービス名は、domainUID(domain1)とサーバ名から導出されます。

これらのアドレス名はKubernetes名前空間内で解決可能であり、リスンポートとともに各サーバのデフォルトのネットワーク・チャネルを定義するために使用されます。前述のように、デフォルトのネットワーク・チャネルURLはトランザクション・コンテキストとともに伝播され、Transaction Managerによって分散トランザクションの調整のために内部的に使用されます。

Example Application

WebLogic ServerドメインがKubernetesで動作するようになったので、分散トランザクション処理を検証するためのサンプルアプリケーションを見ていきます。できるだけシンプルにするために、サーバー間のトランザクション伝播と同期コールバック処理の範囲をサンプルでは制限しています。これにより、リソースマネージャーの設定、JDBCやJMSクライアントコードを記述するという複雑な作業をしなくても、サーバー間のトランザクション通信を検証できます。

アプリケーションは、ServletフロントエンドとRMIリモートオブジェクトの2つの主要コンポーネントで構成されています。Servletは、URLのリストを含むGETリクエストを処理します。グローバルトランザクションを開始し、各URLでリモートオブジェクトを呼び出します。リモートオブジェクトは、単純に、beforeCompletionおよびafterCompletionコールバックメソッドで標準出力にメッセージを出力する同期コールバックを登録します。最後に、Servletはトランザクションをコミットし、各RMI呼び出しに関する情報とグローバルトランザクションの結果を含むレスポンスを送信します。

下図は、Kubernetesクラスタ内のdomain1のサーバ上のサンプルアプリケーションの実行の様子を示しています。Servletは、管理サーバの外部ポートを使って呼び出されます。Servletは、トランザクションを開始し、ローカル同期オブジェクトを登録し、Kubernetesの内部URL t3://domain1-managed-server1:8001 と t3://domain1-managed-server2:8001を使用して、管理対象サーバ上のregisterメソッドを呼び出します 。

TxPropagate Servlet
前述の通り、Servletはトランザクションを開始し、指定された各サーバーURLでRemoteSync.register()リモートメソッドを呼び出します。 その後、トランザクションはコミットされ、結果が呼び出し元に返されます。
package example;

import java.io.IOException;
import java.io.PrintWriter;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;

import weblogic.transaction.Transaction;
import weblogic.transaction.TransactionHelper;
import weblogic.transaction.TransactionManager;

@WebServlet("/TxPropagate")
public class TxPropagate extends HttpServlet {
  private static final long serialVersionUID = 7100799641719523029L;
  private TransactionManager tm = (TransactionManager)
      TransactionHelper.getTransactionHelper().getTransactionManager();

  protected void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();

    String urlsParam = request.getParameter("urls");
    if (urlsParam == null) return;
    String[] urls = urlsParam.split(",");

    try {
      RemoteSync forward = (RemoteSync)
          new InitialContext().lookup(RemoteSync.JNDINAME);
      tm.begin();
      Transaction tx = (Transaction) tm.getTransaction();
      out.println("<pre>");
      out.println(Utils.getLocalServerID() + " started " +
          tx.getXid().toString());
      out.println(forward.register());
      for (int i = 0; i < urls.length; i++) {
        out.println(Utils.getLocalServerID() + " " + tx.getXid().toString() +
            " registering Synchronization on " + urls[i]);
        Context ctx = Utils.getContext(urls[i]);
        forward = (RemoteSync) ctx.lookup(RemoteSync.JNDINAME);
        out.println(forward.register());
      }
      tm.commit();
      out.println(Utils.getLocalServerID() + " committed " + tx);
    } catch (NamingException | NotSupportedException | SystemException |
        SecurityException | IllegalStateException | RollbackException |
        HeuristicMixedException | HeuristicRollbackException e) {
      throw new ServletException(e);
    }
  }
Remote Object
RemoteSyncリモートオブジェクトには、伝播されたトランザクションコンテキストを使ってjavax.transaction.Synchronizationコールバックを登録するメソッドregisterが含まれています。

RemoteSync Interface
The following is the example.RemoteSync remote interface definition.
package example;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RemoteSync extends Remote {
  public static final String JNDINAME = "propagate.RemoteSync";
  String register() throws RemoteException;
}
RemoteSyncImpl Implementation
example.RemoteSyncImplクラスはexample.RemoteSyncリモートインターフェイスを実装し、SynchronizationImplという名前の内部同期実装クラスを含んでいます。beforeCompletionメソッドとafterCompletionメソッドは、単純にサーバーID(ドメイン名とサーバー名)と伝播されたトランザクションのXid文字列表現を含むメッセージを標準出力に書き出します。

staticなmainメソッドは、RemoteSyncImplオブジェクトをインスタンス化し、それをサーバーのローカルJNDIコンテキストにバインドします。 後述のApplicationLifecycleListenerを使用してアプリケーションがデプロイされると、mainメソッドが呼び出されます。
package example;

import java.rmi.RemoteException;

import javax.naming.Context;
import javax.transaction.RollbackException;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;

import weblogic.jndi.Environment;
import weblogic.transaction.Transaction;
import weblogic.transaction.TransactionHelper;

public class RemoteSyncImpl implements RemoteSync {

  public String register() throws RemoteException {
    Transaction tx = (Transaction)
        TransactionHelper.getTransactionHelper().getTransaction();
    if (tx == null) return Utils.getLocalServerID() +
        " no transaction, Synchronization not registered";
    try {
      Synchronization sync = new SynchronizationImpl(tx);
      tx.registerSynchronization(sync);
      return Utils.getLocalServerID() + " " + tx.getXid().toString() +
          " registered " + sync;
    } catch (IllegalStateException | RollbackException |
        SystemException e) {
      throw new RemoteException(
          "error registering Synchronization callback with " +
      tx.getXid().toString(), e);
    }
  }

  class SynchronizationImpl implements Synchronization {
    Transaction tx;
  
    SynchronizationImpl(Transaction tx) {
      this.tx = tx;
    }
  
    public void afterCompletion(int arg0) {
      System.out.println(Utils.getLocalServerID() + " " +
          tx.getXid().toString() + " afterCompletion()");
    }

    public void beforeCompletion() {
      System.out.println(Utils.getLocalServerID() + " " +
          tx.getXid().toString() + " beforeCompletion()");
    }
  }

  // create and bind remote object in local JNDI
  public static void main(String[] args) throws Exception {
    RemoteSyncImpl remoteSync = new RemoteSyncImpl();
    Environment env = new Environment();
    env.setCreateIntermediateContexts(true);
    env.setReplicateBindings(false);
    Context ctx = env.getInitialContext();
    ctx.rebind(JNDINAME, remoteSync);
    System.out.println("bound " + remoteSync);
  }
}

Utility Methods
Utilsクラスには、ローカルサーバーIDを取得する静的メソッドとURLを指定して初期コンテキストルックアップを実行する静的メソッドの2つが含まれています。 初期コンテキストルックアップのメソッドは、匿名ユーザーの下で呼び出されます。これらのメソッドは、Servletとリモートオブジェクトの両方で使用されます。
package example;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Utils {

  public static Context getContext(String url) throws NamingException {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,
        "weblogic.jndi.WLInitialContextFactory");
    env.put(Context.PROVIDER_URL, url);
    return new InitialContext(env);
  }

  public static String getLocalServerID() {
    return "[" + getDomainName() + "+"
        + System.getProperty("weblogic.Name") + "]";
  }

  private static String getDomainName() {
    String domainName = System.getProperty("weblogic.Domain");
    if (domainName == null) domainName = System.getenv("DOMAIN_NAME");
    return domainName;
  }
}

ApplicationLifecycleListener
アプリケーションがWebLogic Serverインスタンスにデプロイされると、ApplicationLifecycleListenerのpreStartメソッドが呼び出され、RemoteSyncリモートオブジェクトが初期化され、バインドされます。
package example;

import weblogic.application.ApplicationException;
import weblogic.application.ApplicationLifecycleEvent;
import weblogic.application.ApplicationLifecycleListener;

public class LifecycleListenerImpl extends ApplicationLifecycleListener {

  public void preStart (ApplicationLifecycleEvent evt)
      throws ApplicationException {
    super.preStart(evt);
    try {
      RemoteSyncImpl.main(null);
    } catch (Exception e) {
      throw new ApplicationException(e);
    }
  }
}
Application Deployment Descriptor
アプリケーション・アーカイブには、ApplicationLifecycleListenerを登録するための以下のweblogic-application.xmlデプロイメント記述子が含まれています。
<?xml version = '1.0' ?>
<weblogic-application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-application http://www.bea.com/ns/weblogic/weblogic-application/1.0/weblogic-application.xsd" xmlns="http://www.bea.com/ns/weblogic/weblogic-application">
   <listener>
    <listener-class>example.LifecycleListenerImpl</listener-class>
    <listener-uri>lib/remotesync.jar</listener-uri>
  </listener>
</weblogic-application>
Deploying the Application
このサンプルアプリケーションは、サポートされている数多くのデプロイ方式を使用してデプロイすることができますが、この例では、WebLogic Server管理コンソールを使用してアプリケーションをデプロイします。
Best Practices for Application Deployment on WebLogic Server Running on Kubernetes
https://blogs.oracle.com/weblogicserver/best-practices-for-application-deployment-on-weblogic-server-running-on-kubernetes-v2https://orablogs-jp.blogspot.com/2018/01/best-practices-for-application.html
アプリケーションがtxpropagate.earという名前のアプリケーションアーカイブにパッケージされているとします。まず、txpropagate.earをdomain1の永続的なボリュームの下にあるapplicationsディレクトリ($K8SOP/volumes/domain1/applications)にコピーすると、管理コンソールの[デプロイメント]ページからアプリケーションをデプロイできます。

EARファイルのパスは、管理サーバのコンテナ内の/shared/applications/txpropagate.earです。ここで/sharedは、$K8SOP/volumes/domain1に作成した永続ボリュームにマップされます。

EARをアプリケーションとしてデプロイし、管理サーバおよびクラスタをデプロイ先として設定します。

次のページで、Finishをクリックしてアプリケーションをデプロイします。アプリケーションのデプロイ後、デプロイメント表にエントリを確認できます。


Running the Application
domain1のサーバーにアプリケーションをデプロイしたので、分散トランザクションのテストを実行できます。以下のcURL操作では、クラスタに属する管理対象サーバのロード・バランサ・ポート30305を使用してServletを起動しています。その際、managed-server1のURLを指定します。
$ curl http://localhost:30305/TxPropagate/TxPropagate?urls=t3://domain1-managed-server1:8001

[domain1+managed-server2] started BEA1-0001DE85D4EE[domain1+managed-server2] BEA1-0001DE85D4EEC47AE630 registered example.RemoteSyncImpl$SynchronizationImpl@562a85bd
[domain1+managed-server2] BEA1-0001DE85D4EEC47AE630 registering Synchronization on t3://domain1-managed-server1:8001
[domain1+managed-server1] BEA1-0001DE85D4EEC47AE630 registered example.RemoteSyncImpl$SynchronizationImpl@585ff41b
[domain1+managed-server2] committed Xid=BEA1-0001DE85D4EEC47AE630(844351585),Status=Committed,numRepliesOwedMe=0,numRepliesOwedOthers=0,seconds since begin=0,seconds left=120,useSecure=false,SCInfo[domain1+managed-server2]=(state=committed),SCInfo[domain1+managed-server1]=(state=committed),properties=({ackCommitSCs={managed-server1+domain1-managed-server1:8001+domain1+t3+=true}, weblogic.transaction.partitionName=DOMAIN}),OwnerTransactionManager=ServerTM[ServerCoordinatorDescriptor=(CoordinatorURL=managed-server2+domain1-managed-server2:8001+domain1+t3+ CoordinatorNonSecureURL=managed-server2+domain1-managed-server2:8001+domain1+t3+ coordinatorSecureURL=null, XAResources={WSATGatewayRM_managed-server2_domain1},NonXAResources={})],CoordinatorURL=managed-server2+domain1-managed-server2:8001+domain1+t3+)
下図がそのアプリケーションフローです。

出力を見ると、ServletリクエストがBEA1-0001DE85D4EEトランザクションを開始したmanaged-server2にディスパッチされたことがわかります。
[domain1+managed-server2] started BEA1-0001DE85D4EE
ローカルのRemoteSync.register()メソッドが呼び出され、コールバックオブジェクトSynchronizationImpl@562a85bdが登録されました。
[domain1+managed-server2] BEA1-0001DE85D4EEC47AE630 registered example.RemoteSyncImpl$SynchronizationImpl@562a85bd
Servletはmanaged-server1上のRemoteSyncオブジェクトのregisterメソッドを呼び出し、同期オブジェクトSynchronizationImpl@585ff41bを登録しました。
[domain1+managed-server2] BEA1-0001DE85D4EEC47AE630 registering Synchronization on t3://domain1-managed-server1:8001
[domain1+managed-server1] BEA1-0001DE85D4EEC47AE630 registered example.RemoteSyncImpl$SynchronizationImpl@585ff41b
最後に、Servletはトランザクションをコミットし、トランザクションの文字列表現(通常はTransaction Managerのデバッグログに使用)を返します。
[domain1+managed-server2] committed Xid=BEA1-0001DE85D4EEC47AE630(844351585),Status=Committed,numRepliesOwedMe=0,numRepliesOwedOthers=0,seconds since begin=0,seconds left=120,useSecure=false,SCInfo[domain1+managed-server2]=(state=committed),SCInfo[domain1+managed-server1]=(state=committed),properties=({ackCommitSCs={managed-server1+domain1-managed-server1:8001+domain1+t3+=true}, weblogic.transaction.partitionName=DOMAIN}),OwnerTransactionManager=ServerTM[ServerCoordinatorDescriptor=(CoordinatorURL=managed-server2+domain1-managed-server2:8001+domain1+t3+ CoordinatorNonSecureURL=managed-server2+domain1-managed-server2:8001+domain1+t3+ coordinatorSecureURL=null, XAResources={WSATGatewayRM_managed-server2_domain1},NonXAResources={})],CoordinatorURL=managed-server2+domain1-managed-server2:8001+domain1+t3+)
出力からは以下のことがわかります。
  • トランザクションがコミットされた
  • 2個のサーバー参加者(managed-server1およびmanaged-server2)
  • t3://domain1-managed-server2:8001を使用してコーディネート・サーバ(managed-server2)にアクセス可能
admin-serverおよびmanaged-server1の出力を調べると、登録された同期コールバックが呼び出されたことを確認することもできます。サーバの.outファイルは、ドメインの永続ボリュームの下にあります。
$ cd $K8SOP/volumes/domain1/domain/domain1/servers
$ find . -name '*.out' -exec grep -H BEA1-0001DE85D4EE {} ';'
./managed-server1/logs/managed-server1.out:[domain1+managed-server1] BEA1-0001DE85D4EEC47AE630 beforeCompletion()
./managed-server1/logs/managed-server1.out:[domain1+managed-server1] BEA1-0001DE85D4EEC47AE630 afterCompletion()
./managed-server2/logs/managed-server2.out:[domain1+managed-server2] BEA1-0001DE85D4EEC47AE630 beforeCompletion()
./managed-server2/logs/managed-server2.out:[domain1+managed-server2] BEA1-0001DE85D4EEC47AE630 afterCompletion()
まとめると、何も変更せずに、Kubernetesクラスタで実行されているWebLogic Serverドメイン内で分散トランザクションを処理できました。 WebLogic Kubernetes Operatorのドメイン作成プロセスは、作成に必要なKubernetesネットワークとWebLogic Serverのすべての設定を提供しました。

以下のコマンドは、weblogic名前空間で定義されたKubernetesサービスを表示します。
$ kubectl get svc -n weblogic
NAME                                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)           AGE
domain1-admin-server                        NodePort    10.102.156.32    <none>        7001:30701/TCP    11m
domain1-admin-server-extchannel-t3channel   NodePort    10.99.21.154     <none>        30012:30012/TCP   9m
domain1-cluster-1-traefik                   NodePort    10.100.211.213   <none>        80:30305/TCP      11m
domain1-cluster-1-traefik-dashboard         NodePort    10.108.229.66    <none>        8080:30315/TCP    11m
domain1-cluster-cluster-1                   ClusterIP   10.106.58.103    <none>        8001/TCP          9m
domain1-managed-server1                     ClusterIP   10.108.85.130    <none>        8001/TCP          9m
domain1-managed-server2                     ClusterIP   10.108.130.92    <none>        8001/TCP
localhost上のポート30305を使用してTraefik NodePortサービスを通じてServletにアクセスできました。 Kubernetesクラスタ内から、Servletはサービス名とポートを使用して他のWebLogic Serverインスタンスにアクセスできます。各サーバーのリスンアドレスは対応するKubernetesサービス名に設定されているため、サーバーのPodが再起動され、別のIPアドレスが割り当てられても、Kubernetes名前空間からアドレスを解決できます。

Cross-Domain Transactions

それでは、このサンプルを2個のWebLogic Serverドメインで実行するように拡張します。Transaction Manager概要の章で説明したように、クロスドメイン・トランザクションでは、Transaction Manager通信を適切に保護するために追加の設定が必要になることがあります。ただし、この例では、構成をできるだけシンプルに保つことを目的として、アプリケーションと内部Transaction Manager通信の両方に対して、非セキュアプロトコル(t3)と匿名ユーザーを引き続き使用します。

まず、domain1(weblogic)と同じKubernetes名前空間に新しいドメイン(domain2)を作成する必要があります。 domain2を生成する前に、weblogic名前空間のdomain2資格証明のためのシークレット(domain2-weblogic-credentials)と、永続的ボリュームのディレクトリ($K8SOP/volumes/domain2)を作成する必要があります。

続いて、 create-domain1.yaml ファイルを変更します。以下の属性値を変更後、create-domain2.yaml としてファイルを保存します。
AttributeValue
domainNamedomain2
domainUIDdomain2
weblogicDomainStoragePath{full path of $HOME}/k8sop/volumes/domain2
weblogicCredentialsSecretNamedomain2-weblogic-credentials
t3ChannelPort32012
adminNodePort32701
loadBalancerWebPort32305
loadBalancerDashboardPort32315
これで、create-domain2.yamlファイルを使ってをcreate-weblogic-domain.shスクリプトを起動できる準備が整いました。
$ $K8SOP/src/weblogic-kubernetes-operator/kubernetes/create-weblogic-domain.sh -i $K8SOP/create-domain2.yaml -o $K8SOP/weblogic-kubernetes-operator
createスクリプトが正常終了すると、domain2のサーバが開始し、readinessプローブを使ってRUNNING状態に到達したことを報告します。
$ kubectl get po -n weblogic
NAME                                         READY     STATUS    RESTARTS   AGE
domain1-admin-server                         1/1       Running   0          27m
domain1-cluster-1-traefik-9985d9594-gw2jr    1/1       Running   0          27m
domain1-managed-server1                      1/1       Running   0          25m
domain1-managed-server2                      1/1       Running   0          25m
domain2-admin-server                         1/1       Running   0          5m
domain2-cluster-1-traefik-5c49f54689-9fzzr   1/1       Running   0          5m
domain2-managed-server1                      1/1       Running   0          3m
domain2-managed-server2                      1/1       Running   0          3m
domain2のサーバにアプリケーションをデプロイ後、アプリケーションを呼び出し、domain2の管理対象サーバのURLを含めることができます。
$ curl http://localhost:30305/TxPropagate/TxPropagate?urls=t3://domain2-managed-server1:8001,t3://domain2-managed-server2:8001

[domain1+managed-server1] started BEA1-0001144553CC
[domain1+managed-server1] BEA1-0001144553CC5D73B78A registered example.RemoteSyncImpl$SynchronizationImpl@2e13aa23
[domain1+managed-server1] BEA1-0001144553CC5D73B78A registering Synchronization on t3://domain2-managed-server1:8001
[domain2+managed-server1] BEA1-0001144553CC5D73B78A registered example.RemoteSyncImpl$SynchronizationImpl@68d4c2d6
[domain1+managed-server1] BEA1-0001144553CC5D73B78A registering Synchronization on t3://domain2-managed-server2:8001
[domain2+managed-server2] BEA1-0001144553CC5D73B78A registered example.RemoteSyncImpl$SynchronizationImpl@1ae87d94
[domain1+managed-server1] committed Xid=BEA1-0001144553CC5D73B78A(1749245151),Status=Committed,numRepliesOwedMe=0,numRepliesOwedOthers=0,seconds since begin=0,seconds left=120,useSecure=false,SCInfo[domain1+managed-server1]=(state=committed),SCInfo[domain2+managed-server1]=(state=committed),SCInfo[domain2+managed-server2]=(state=committed),properties=({ackCommitSCs={managed-server2+domain2-managed-server2:8001+domain2+t3+=true, managed-server1+domain2-managed-server1:8001+domain2+t3+=true}, weblogic.transaction.partitionName=DOMAIN}),OwnerTransactionManager=ServerTM[ServerCoordinatorDescriptor=(CoordinatorURL=managed-server1+domain1-managed-server1:8001+domain1+t3+ CoordinatorNonSecureURL=managed-server1+domain1-managed-server1:8001+domain1+t3+ coordinatorSecureURL=null, XAResources={WSATGatewayRM_managed-server1_domain1},NonXAResources={})],CoordinatorURL=managed-server1+domain1-managed-server1:8001+domain1+t3+)
アプリケーションフローを下図に示します。

この例では、トランザクションにはdomain1とdomain2の両方からのサーバー参加者が含まれ、同期コールバックが全ての参加サーバで処理されたことを確認できます。
$ cd $K8SOP/volumes
$ find . -name '*.out' -exec grep -H BEA1-0001144553CC {} ';'
./domain1/domain/domain1/servers/managed-server1/logs/managed-server1.out:[domain1+managed-server1] BEA1-0001144553CC5D73B78A beforeCompletion()
./domain1/domain/domain1/servers/managed-server1/logs/managed-server1.out:[domain1+managed-server1] BEA1-0001144553CC5D73B78A afterCompletion()
./domain2/domain/domain2/servers/managed-server1/logs/managed-server1.out:[domain2+managed-server1] BEA1-0001144553CC5D73B78A beforeCompletion()
./domain2/domain/domain2/servers/managed-server1/logs/managed-server1.out:[domain2+managed-server1] BEA1-0001144553CC5D73B78A afterCompletion()
./domain2/domain/domain2/servers/managed-server2/logs/managed-server2.out:[domain2+managed-server2] BEA1-0001144553CC5D73B78A beforeCompletion()
./domain2/domain/domain2/servers/managed-server2/logs/managed-server2.out:[domain2+managed-server2] BEA1-0001144553CC5D73B78A afterCompletion()

Summary

このエントリでは、WebLogic ServerのTransaction Managerがグローバルトランザクションをどのように処理するかを確認し、いくつかの基本的な設定要件について説明しました。続いて、サンプルアプリケーションを使って、Kubernetesクラスタでクロスドメイントランザクションがどのように処理されるかを見てきました。今後は、マルチノード、クロスKubernetesクラスタのトランザクション、フェールオーバーなど、より複雑なトランザクションのユースケースを見ていきます。

[Linux] Resilient RDMA IP Addresses

原文はこちら。
https://blogs.oracle.com/linux/resilient-rdma-ip-addresses

RDSのResilient RDMA IP機能をアップストリームへ導入するために実施している作業に関する記事を、Oracle Linuxカーネルの開発者Sudhakar Dindukurtiが寄稿しました。このコードは現在、OracleのオープンソースのUEKカーネルで管理されており、これを上流のLinuxソースコードに統合する作業を進めています。

1.0 Introduction to Resilient RDMA IP

Resilient RDMAIPモジュールは、InfiniBandおよびRoCEアダプタのフェールオーバー、フェールバック、および負荷分散を行うために、ULP(RDMA上位レベルプロトコル)を支援します。

RDMAIPは、Oracle LinuxのRDMA接続の機能です。active-active bondingとも呼ばれるこの機能を有効にすると、Resilient RDMAIPモジュールはアダプタのポート間にアクティブなbondingグループを作成します。正常時には利用可能な全帯域幅を使用しながら、ネットワークアダプターが失われた場合、そのポート上のIPは、アプリケーション用にHAを自動的に提供しながら、別のポートに移動されます。

Reliable Datagram Sockets (RDS) は、データグラム伝送のための高パフォーマンスで低レイテンシな信頼できるコネクションレスソケットです。RDSは、2ノード間で信頼性の高い単一のトランスポートを使用して、信頼性の高い順序付けされたデータグラム配信を提供します。RDSプロトコルの詳細については、RDSのドキュメントを参照してください。
RDS Wire Specification 3.1
http://oss.oracle.com/projects/rds/dist/documentation/rds-3.1-spec.html
RDS RDMAは、Resilient RDMAIPモジュールを使用してHAサポートを提供します。RDS RDMAモジュールは、Resilient RDMAIPモジュールが提供するRDMA CMアドレス変更イベントを待ち受けます。RDSは、アドレス変更イベントを受信した場合、接続に失敗したポートに関連付けられているすべてのRC接続を削除し、次回データを送信する前に新しいRC接続を再確立します。

透過的な高可用性は、標準のNIC(ネットワーク・インタフェース・カード)と比較して、RDMA対応NICアダプタにとって重要な問題です。標準的なNICの場合、IP層は、パケット送信のためにどの経路またはどのnetdevインタフェースを使用するかを決定できます。これは、ハードウェアを特定のポートとパスに結び付けるという、セキュリティとパフォーマンス上の理由から、RDMA対応アダプターでは不可能です。RDMAを使用してリモートノードにデータパケットを送信するには、いくつかの手順があります。
  1. クライアントアプリケーションはメモリをRDMAアダプタに登録し、RDMAアダプタは登録されたメモリ領域のR_Keyをクライアントに返す。
    (注意)登録情報はRDMAアダプタに保存される。
  2. クライアントはこの "R_key"をリモートサーバーに送信する。
  3. クライアントへのRDMA_READ/RDMA_WRITEを要求時には、サーバにはこのR_keyが含まれる
  4. クライアント側のRDMAアダプタは、"R_key"を使用してメモリ領域を見つけ出し、トランザクションを進める。"R_key"は特定のRDMAアダプタにバインドされているため、同じR_KEYを使用して別のRDMAアダプタでデータを送信することはできない。また、RDMAアプリケーションはカーネルをバイパスして直接ハードウェアと通信できるため、 (カーネルに備わる)これまでのbondingがHAを提供できない。
Resilient RDMAIPは、カーネルULPまたはOSバイパスアプリケーションに対して透過的なフェールオーバーを提供しませんが、RDMA対応アダプターでのULPのフェールオーバー、フェイルバック、およびロードバランスを可能にします。RDS(Reliable Datagram Sockets)プロトコルは、Resilient RDMAIPモジュールサポートを使用してHAを提供している最初のクライアントです。以下のセクションでは、さまざまな機能に対するResilient RDMAIPの役割について説明します。

1.1 Load balancing

Active-Active bondingグループに含まれる全てのインターフェースには個別のIPアドレスがあります。RDMAコンシューマは1個以上のインターフェースを利用して、同時にデータを送信することができ、全てのアクティブなインターフェース間で負荷を分散させる責任があります。

1.2 Failover

Active-Active Bondingグループに属する任意のインターフェースがダウンした場合、Resilient RDMAIPモジュールはインターフェイスのIPアドレスを同じグループ内の他のインターフェイスに移動し、また、RDMA CM(Communication Manager)アドレス変更イベントをRDMAカーネルULPに送信します。HA対応のRDMAカーネルULPは、ダウンしたインターフェイスの使用を停止し、他のアクティブなインターフェイスの使用を開始します。例えば、ダウンしたインターフェースでReliable Connection(RC)が確立されている場合、ULPはこれらの接続をすべて閉じて、フェールオーバーインターフェイスで再確立できます。

1.3 Failback

ダウンしたインターフェイスが(フェールオーバする前に)先に復旧した場合、Resilient RDMAIPモジュールはIPアドレスを元のインターフェイスに戻し、RDMA CMアドレス変更イベントをカーネルコンシューマに再度送信します。RDMAカーネルのコンシューマは、アドレス変更イベントを受信するとアクションを実行します。例えば、RDMAコンシューマは、フェールオーバーの一環で移動された接続を移動します。

2.0 Resilient RDMAIP module provides the below module parameters

  • rdmaip_active_bonding_enabled

    • Active-Active bondingを有効化する場合は1を設定
    • Active-Active bondingを無効化する場合は0を設定
デフォルトでは、Active-Active bondingは無効化されていますが、有効化すると、Resilient RDMAIPモジュールは、同じRDMAアダプタのポート間でアクティブなbondingグループを作成します。例えば、Infiniband(ib0とib1)とRoCE(eth5とeth5)のそれぞれに2つのポートを有する、2つのRDMAアダプタがあるシステムを考えてみましょう。この設定では、2つのアクティブなbondingグループが作成されます。
1)ib0とib1(Bond 1)
2)eth4とeth5(Bond 2)
  • rdmaip_ipv4_exclude_ips_list

    • このパラメータに記載のあるIPの場合、アクティブbonding機能は無効
デフォルトでは、リンクローカルアドレスはResilient RDMAIPによって除外されます。

3.0 How it works ?

Active-Active Bonding

上図で、1個の2ポートInfiniband HCAを備えた2つのノードがあり、HCAの各ポートは図のように異なるスイッチに接続されています。図に示すように、ポートごとに1つずつ、2つのIPoIBインターフェイス(ib0およびib1)が作成されます。Active-Active bondingを有効化すると、Resilient RDMAIPモジュールは自動的にInfiniband HCAの2つのポート間にbondingを作成します。

1) 全てのIBインターフェースが起動していて構成済み

#ip a
---
ib0: <broadcast,multicast,up,lower_up> mtu 2044 qdisc pfifo_fast state UP qlen 256
    link/infiniband 80:00:02:08:fe:80:00:00:00:00:00:00:00:10:e0:00:01:29:65:01 brd 00:ff:ff:ff:ff:12:40:1b:ff:ff:00:00:00:00:00:00:ff:ff:ff:ff
    inet 10.10.10.92/24 brd 10.10.10.255 scope global ib0
       valid_lft forever preferred_lft forever
  
  
ib1: <broadcast,multicast,up,lower_up> mtu 2044 qdisc pfifo_fast state UP qlen 256
    link/infiniband 80:00:02:09:fe:80:00:00:00:00:00:00:00:10:e0:00:01:29:65:02 brd 00:ff:ff:ff:ff:12:40:1b:ff:ff:00:00:00:00:00:00:ff:ff:ff:ff
    inet 10.10.10.102/24 brd 10.10.10.255 scope global secondary ib0:P06
       valid_lft forever preferred_lft forever </broadcast,multicast,up,lower_up></broadcast,multicast,up,lower_up>

2) Node 1のPort 2がダウンすると、ib1のIP '10.10.10.102'がPort 1(ib0)に移動する(フェールオーバ)

#ip a
--------------
 ib0: <broadcast,multicast,up,lower_up> mtu 2044 qdisc pfifo_fast state UP qlen 256
    link/infiniband 80:00:02:08:fe:80:00:00:00:00:00:00:00:10:e0:00:01:29:65:01 brd 00:ff:ff:ff:ff:12:40:1b:ff:ff:00:00:00:00:00:00:ff:ff:ff:ff
    inet 10.10.10.92/24 brd 10.10.10.255 scope global ib0
       valid_lft forever preferred_lft forever
    inet 10.10.10.102/24 brd 10.10.10.255 scope global secondary ib0:P06
       valid_lft forever preferred_lft forever
    inet6 fe80::210:e000:129:6501/64 scope link
       valid_lft forever preferred_lft forever
ib1: <no-carrier,broadcast,multicast,up> mtu 2044 qdisc pfifo_fast state DOWN qlen 256
    link/infiniband 80:00:02:09:fe:80:00:00:00:00:00:00:00:10:e0:00:01:29:65:02 brd 00:ff:ff:ff:ff:12:40:1b:ff:ff:00:00:00:00:00:00:ff:ff:ff:ff
----------------
</no-carrier,broadcast,multicast,up></broadcast,multicast,up,lower_up>

3) Node 1のPort 2が復旧すると、Port 2 (ib1)にIP '10.10.10.102'が戻る(フェールバック)

#ip a
---
ib0: <broadcast,multicast,up,lower_up> mtu 2044 qdisc pfifo_fast state UP qlen 256
    link/infiniband 80:00:02:08:fe:80:00:00:00:00:00:00:00:10:e0:00:01:29:65:01 brd 00:ff:ff:ff:ff:12:40:1b:ff:ff:00:00:00:00:00:00:ff:ff:ff:ff
    inet 10.10.10.92/24 brd 10.10.10.255 scope global ib0
       valid_lft forever preferred_lft forever
  
  
 ib1: <broadcast,multicast,up,lower_up> mtu 2044 qdisc pfifo_fast state UP qlen 256
    link/infiniband 80:00:02:09:fe:80:00:00:00:00:00:00:00:10:e0:00:01:29:65:02 brd 00:ff:ff:ff:ff:12:40:1b:ff:ff:00:00:00:00:00:00:ff:ff:ff:ff
      inet 10.10.10.102/24 brd 10.10.10.255 scope global secondary ib0:P06
       valid_lft forever preferred_lft forever
</broadcast,multicast,up,lower_up></broadcast,multicast,up,lower_up>

Example: RDS Implementation

フェイルオーバーおよびフェールバック中に発生するシーケンスを次に示します。ノード1のPort 1のIP1とノード2のIP3との間にRDSソケットを確立するRDSアプリケーションを考えます。この場合、RDSカーネルレベルでは、IP1とIP3の間に1つのRC接続が存在します。

Case 1: Node 1のPort 1がダウン

  • Resilient RDMAIPモジュールがIPアドレスIP1をポート1からポート2に移動
  • ポート2は2つのIP(IP1とIP2)を持つ
  • Resilient RDMAIPモジュールは、RDMA CMアドレス変更イベントをRDSに送信
  • RDS RDMAドライバは、アドレス変更イベントの処理の一環で、IP1(Port 1)とIP3の間のIB接続を切断
  • RDS RDMAドライバは、IP1からIP3への新たな送信リクエストを受信すると、IP1(Port 2)とIP3との間で新しいRC接続を作成
  • フェイルオーバー後、RDSがIP1を解決すると、IP1がPort 2にバインドされるため、RDSはPort 2のパスレコードを取得

Case 2: Node 1のPort 1が復旧

  • Resilient RDMAIPモジュールは、IPアドレスIP1をPort 2からPort 1に移動
  • Resilient RDMAIPモジュールは、RDMA CMアドレス変更イベントをRDSに送信
  • RDS RDMAドライバは、アドレス変更イベントの処理の一環で、IP1(Port 2)とIP3の間のIB接続を切断
  • RDS RDMAドライバは、IP1からIP3への新しい送信要求を受信すると、IP1(Port 1)からIP3への新しいRC接続を作成
  • フェールバック後、RDSがIP1を解決すると、IP1がPort 1にバインドされるため、RDSはPort 1のパスレコードを取得

4.0 Future work

Resilient RDMAIPモジュールの現在の実装は、ネットワークスタック実装と密接に結びついていません。例えば、RDMAカーネルコンシューマは、アクティブなBondingグループを作成する方法を有しておらず、また、アクティブなBondingグループやどのインターフェースがアクティブなBondingグループで構成されているのかをRDMAコンシューマに通知できるAPIはありません。結果として、現在の設計や実装はアップストリームに導入するには適していません。そのため、このモジュールのアップストリームのLinuxに提出可能なバージョンの開発に現在取り組んでいます。しかしながら、それまでの間はRDASIPのコードはoss.oracle.comとgithub上にあります。
Oracle Linux UEK: Unbreakable Enterprise Kernel
http://github.com/oracle/linux-uek

[Linux] Announcing Release 3 of Ceph Storage for Oracle Linux

原文はこちら。
https://blogs.oracle.com/linux/announcing-release-3-of-ceph-storage-for-oracle-linux

Ceph Storage for Oracle Linux Release 3を発表できうれしく思っています。このリリースでは、複数の物理的および論理的な汎用ハードウェアストレージデバイスのクラスタから、オブジェクトストレージおよびブロックストレージの統一されたビューが提供されます。Cephは、Ceph Storage Cluster内のストレージデバイス間でデータを複製およびストライピングすることにより、フォールトトレランスを提供し、I/Oパフォーマンスを向上させます。Cephの監視機能と自己修復機能により、管理オーバーヘッドを最小限に抑えられます。

Ceph Storage for Oracle Linux Release 3は、Ceph Community Luminousリリース(v12.2.5)に基づいています。 Oracleバージョンのソフトウェアとアップストリーム・リリースの違いは、特定のバグに対するOracle固有の修正およびパッチに限られます。

サポートされる機能には、Object Store、Block Device、Ceph Storage Cluster、Ceph File System(Ceph FS)、Simple Ceph Object Gateway、およびMultisite Ceph Object Gatewayコンポーネントがあります。

Notable new features:

  • クラスタ監視のためのCeph Managerデーモン(ceph-mgr)
  • WebベースのCeph Managerダッシュボード
  • HDDやSSDを管理するためにBlueStoreバックエンドを使うOSD(Object Storage Daemon)
  • OSD置換プロセスの簡略化 

Release 3 of Ceph Storage for Oracle Linux adds support for:

  • Ceph iSCSI gateway
  • Ceph FS
  • Ceph FSファイルシステムやblock storage over NFSのエクスポート
  • Ceph block devices with QEMU

Supported Upgrade Path

アップグレード手順は、製品ドキュメントのUpgradeに関する章を参照してください。

Product Support

Ceph Storage for Oracle Linux Release 3は、以前のリリースの2.0を置き換えるものです。Ceph Storage for Oracle Linux Release 3.0は、Unbreakable Enterprise Kernel Release 5を実行するOracle Linux 7(x86_64)で使用できます。Oracle Linux 7 Update 5が最小要件です。Release 3.0のceph-deploymentパッケージは、ULNまたはOracle Linux yumサーバーから入手できます。

Resources – Oracle Linux

Documentation

Software Download

Blogs

Community Pages

Social Media

Data Sheets, White Papers, Videos, Training, Support & more

[Linux] Latest Oracle Linux 7.5 and 6.10 Vagrant Boxes Now Available

原文はこちら。
https://blogs.oracle.com/linux/latest-oracle-linux-75-and-610-vagrant-boxes-now-available

Oracle VM VirtualBox用のOracle Linux Vagrant Boxが、Oracle Linux 7.5 + Unbreakable Enterprise Kernel release 5とOracle Linux 6.10にアップデートされました。
Oracle Linux Vagrant Boxes
https://yum.oracle.com/boxes
これらのVagrant Boxには以下のものが含まれています。
  • 最新のカーネル
    • Oracle Linux 7: UEK5 (4.14.35-1818.0.9.el7uek.x86_64)
    • Oracle Linux 6: UEK4 (4.1.12-124.16.4.el6uek.x86_64)
  • VirtualBox guest additions RPMインストール済み
  • Minimal package setインストール済み
  • rootボリューム:32 GB(XFS)
  • Swap:4 GB
  • VirtualBoxディスクイメージ16GB(動的割り当て)をアタッチ済み
完全な最新の詳細情報は以下から確認してください。
Oracle Linux Vagrant Boxes
https://yum.oracle.com/boxes

VirtualBox Guest Addition RPMs

昨年、VirtualBox Guest AdditionのRPM版を導入しました。これにより、必須のドライバやゲストOS最適化機能のインストールやアップグレードが簡単になりました。今回のVagrant BoxではGuest AdditionのRPMは事前インストール済みです。

Get Up and Running Quickly with Pre-configured Software Stacks: Vagrantfiles on GitHub

Oracle Database、Docker、Kubernetesを試してみたいけれど、インストールの詳細に悩まされたくない、さくっと始めたいと思っているなら、GitHubのVagrantfilesにUpしたVagrantファイルをお使いください。
Official source for Vagrant configuration files and examples for Oracle products and projects
https://github.com/oracle/vagrant-boxes
例えば、以下のようなVagrantfilesと手順書がありますので、インストールや構成が簡単です。

References

[Cloud] Announcing Oracle Cloud Infrastructure Ansible Modules

原文はこちら。
https://blogs.oracle.com/cloud-infrastructure/announcing-oracle-cloud-infrastructure-ansible-modules

Oracle Cloud InfrastructureのAnsibleモジュールが公開されたことを発表できうれしく思っています。

より多くのお客様がOracle Cloud Infrastructureにアプリケーションをデプロイするにつれて、これらの操作を自動化するためのDevOps機能の必要性が増していると見ています。Ansibleはこうしたニーズに対応するもので、リソースのプロビジョニングと構成を自動化します。この新たなOracle Cloud Infrastructure Ansibleモジュールは、Oracle Cloud Infrastructureリソースをプロビジョニングし、構成する機能を提供します。現在のリリースですべてのコア・サービスをサポートします(将来のリリースではさらに多くのサービスが対象となります)。またAnsibleには、Oracle Cloud Infrastructure Ansibleモジュールと連携して、エンドツーエンドのニーズを満たすために利用可能な、組み込みモジュールのツールボックスが含まれています。
Ansible Module Index
http://docs.ansible.com/modules_by_category.html
Ansibleは、複雑なエージェントや、セキュリティのカスタマイズ、集中構成サーバーの設定は不要で、自動化するジョブを記述するだけでOKです。Oracle Cloud Infrastructureのリソースをプロビジョニングして構成するには、Ansibleのplaybookを使用して、必要な状態を宣言します。これらのplaybookをAnsibleが実行すると、要件に応じてOracle Cloud Infrastructureのリソースがプロビジョニングおよび構成されます。

Oracle Cloud Infrastructure AnsibleモジュールはGitHubのoci-ansible-modulesリポジトリにあり、マニュアルではサポート対象のモジュールのリストを参照できます。これらのモジュールおよび将来の改善についてのご意見をお待ちしております。oci-ansible-modulesのGitHubのIssueページで皆さんの意見を書き込んでください。
Oracle Cloud Infrastructure (OCI) Ansible Modules
https://github.com/oracle/oci-ansible-modules
Ansible Modules for Oracle Cloud Infrastructure
https://docs.cloud.oracle.com/iaas/Content/API/SDKDocs/ansible.htm
Oracle Cloud Infrastructure (OCI) Ansible ModulesのIssueページ
https://github.com/oracle/oci-ansible-modules/issues

Getting Started

  1. Python SDKをインストール
    Python SDK for Oracle Cloud Infrastructure
    https://github.com/oracle/oci-python-sdk#installation
    pip install oci
  2. Oracle Cloud Infrastructureの資格証明を使ってSDKを構成
    SDK and Tool Configuration
    https://docs.cloud.oracle.com/iaas/Content/API/Concepts/sdkconfig.htm
  3. AnsibleインストールガイドにしたがってAnsibleをインストール
    Installation Guide
    https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
  4. Ansibleモジュールリポジトリをクローン
    $ git clone https://github.com/oracle/oci-ansible-modules.git
    $ cd oci-ansible-modules
  5. 以下のコマンドの一つを実行してAnsibleモジュールをインストール
    • root以外のユーザーでAnsibleをインストールした場合
      $ ./install.py
    • rootでAnsibleをインストールした場合
      $ sudo ./install.py
  6. サンプルのplaybook(例えばlist_buckets)を作成して実行
    Write a sample playbook
    https://docs.cloud.oracle.com/iaas/Content/API/SDKDocs/ansiblegetstarted.htm?tocpath=Developer%20Tools%20%7CAnsible%20Modules%20for%20Oracle%20Cloud%20Infrastructure%7C_____1#writeSample
    $ ansible-playbook list_buckets.yml

詳細は、以下のリソースをご覧ください。
以下のチャネルもお役にたつかもしれません。

[Linux] Translating Process ID between Namespaces

原文はこちら。
https://blogs.oracle.com/linux/translating-process-id-between-namespaces

pid(プロセスID)を異なる名前空間の間で変換する課題に関する、Oracle Linuxのカーネル開発者であるNagarathnam Muthusamyによる寄稿です。これはLinuxカーネルの名前空間サポートには現在ない機能ですが、CDBを使ってOracle Databaseのマルチテナント利用を実現するために重要な機能です。
Oracle Database 12c Feature: Multitenant Database
http://www.oracle.com/technetwork/articles/database/multitenant-part1-pdbs-2193987.html
LinuxカーネルのプロセスID(PID)名前空間機能は、プロセス・グループ間で分離を提供する効果的な方法で、さまざまなコンテナの実装で利用されてきました。プロセス間の強力な分離が求められていますが、システム内の他のプロセスの活動やリソースの利用状況を監視したいプロセスが常に存在します。PID名前空間の各々には独自のPIDシーケンスがあり、プロセスIDと独自のPID名前空間との間で相互変換するために、階層の先頭からプロセスを監視するためのプロセスが必要です。Linuxカーネルには、結果PIDを返すさまざまなAPIセットがありますが、これらのAPIはいずれもPID変換に使用できます。以下でその方法をご紹介します。

SCM_CREDENTIALS:

送信側は、SCM_CREDENTIALSメッセージを送受信して、自身の名前空間のPIDをターゲットの名前空間のPIDに変換できます。この方法の欠点は、PID変換に対するソケット通信チャネルが必要で、その管理オーバーヘッドが増える点です。このメソッドは、ルートでない、もしくはCAP_SYS_ADMINを持たない限り、送信側が他のプロセスのPIDを変換できません。
unix - sockets for local interprocess communication
http://man7.org/linux/man-pages/man7/unix.7.html

/proc/<pid>/status file

/proc/<pid>/statusファイルは、異なる名前空間のプロセスに関連付けられたPIDを見つける方法を提供します。親名前空間からの、親名前空間から子名前空間へのPID変換は、所望のレベルで所望のPIDを見つけるために、親名前空間内のすべてのstatusファイルを検索する必要があります。
proc - process information pseudo-filesystem
http://man7.org/linux/man-pages/man5/proc.5.html
Patchwork [resend,v10,1/2] /proc/PID/status: show all sets of pid according to nslogin
https://patchwork.kernel.org/patch/5861791/

shmctl(..,IPC_STAT,..), msgctl(..,IPC_STAT,..)

共有メモリのIPC_STATが提供する構造体shmid_dsには、以下の2要素が含まれています。
pid_t           shm_cpid;    /* PID of creator */
pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
メッセージキューのIPC_STATが提供する構造体struct msqid_dsには、 以下の2要素が含まれています。
pid_t           msg_lspid;    /* PID of last msgsnd(2) */
pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
これらの要素のPIDは、呼び出し元のPID名前空間に変換されます。名前空間にかかわらず、プロセス共有リソースの利用状況を監視するために監視側がこれらのPIDを利用できますが、共有メモリやメッセージキューを作成せずに、これらのAPIを汎用的なPID変換のために利用することはできません。
shmctl - System V shared memory control
http://man7.org/linux/man-pages/man2/shmctl.2.html
msgctl - System V message control operations
http://man7.org/linux/man-pages/man2/msgctl.2.html

semctl(..,GETPID,..)

semctlのGETPIDコマンドは、セマフォに対して最後の操作を実行したプロセスのPIDを提供します。shmctlおよびmsgctlと同様に、これはセマフォのユーザを監視する優れた方法ですが、セマフォを作成しないで汎用PID変換に使用することはできません。shmctlとsemctlはアップストリームのLinuxカーネル4.17で修正されました。この機能は、旧リリースでは使用できない可能性がありますが、Oracle UEKに取り込まれる予定です。
semctl - System V semaphore control operations
http://man7.org/linux/man-pages/man2/semctl.2.html

fcntl(..,F_GETLK,..)

fcntlのF_GETLKコマンドは、ファイルロック保持中のプロセスに関する情報を提供します。この情報は、呼び出し元の名前空間に変換されます。異なるPID名前空間を通じた変換を必要とするプロセスは、ロック可能な共通の場所にダミーファイルを作成できます。fcntlを使ったファイルロック所有者に関する問い合わせは、呼び出し元の名前空間の下で観測されるプロセスの変換後のPIDを返します。確かにファイルはどのIPCメカニズムよりも軽量ですが、PID変換のためだけにシステム内のすべてのプロセスのファイル作成とクリーンアップという、追加のオーバーヘッドが必要です。

Is there any cleaner way?

通常、監視プロセスやシステム内の他のプロセスでPID変換が必要な場合、前述の方法のいずれかを使用してこの問題を回避できます。上記のオプションのいずれもあなたのユースケースを満足しない場合ですが、その状況はあなただけではありません。

私はKonstantinと協力して、translate_pidという新しいシステムコールを使いPID変換機能を提供する古いパッチを復活させました。この議論は以下のURLで追いかけることができます。このリンクには、APIの以前のバージョンへのポインタもあります。
[PATCH RFC v5] pidns: introduce syscall translate_pid
https://lkml.org/lkml/2018/4/4/677
このAPIは以下の関数シグネチャを伴って動き始めました。
pid_t getvpid(pid_t pid, pid_t source, pid_t target)
ここで強調されている大きな問題は、名前空間を識別するためのPIDの使用でした。PIDを使うすべてのAPIは、PIDの再利用に関わる競合状態の影響を受けやすいのですが、Linuxカーネルには、それらのインタフェースが設計されたときにリソースを識別する優れた方法がなかったために、多くの既存のPIDベースのインタフェースしか持っていませんでした。この提案は次のAPIにつながります。
pid_t translate_pid(pid_t pid, int source, int target);
ここで、sourceとtargetは、ソースとターゲットの名前空間の/proc/<pid>/ns/pidファイルを指すファイル記述子です。このAPIの大きな問題は、すべてのPID変換のためにファイルの開閉に関する追加ステップです。このAPIは、PID変換を必要とするが、/proc/<pid>/ns/pidファイルを開く権限を持たないユースケースでも利用できません。

このブログを書いている時点で議論中のAPIは、以下のように両方の世界の最善を取り込もうとしています。
pid_t translate_pid(pid_t pid, int source_type, int source, int target_type, int target);
ここで、以下のように *type 引数を使って、ソースとターゲットを解釈する方法を変更します。
TRANSLATE_PID_CURRENT_PIDNS //現在のPID名前空間、引数を使わない
TRANSLATE_PID_TASK_PIDNS //task pid-ns、引数はtask pid
TRANSLATE_PID_FD_PIDNS //pidns fd、引数はファイル記述子
APIが完成すると、他の既存のメソッドの問題を回避しない、PIDを変換するためのよりクリーンなメソッドが用意されることでしょう。

[Network] Openswan on Oracle Cloud Infrastructure

原文はこちら
https://blogs.oracle.com/cloud-infrastructure/openswan-on-oracle-cloud-infrastructure

Oracle Cloud Infrastructureなどのクラウド・プロバイダを使用してオンプレミス・サービスを移行または統合するユーザーは、通常、IPセキュリティ(IPSec)テクノロジを使用して環境間で暗号化トンネルを作成し、データ転送やアプリケーションの統合を行います。
IaaS - Enterprise Cloud - Oracle Cloud Infrastructure
http://cloud.oracle.com/iaas
OpenswanのようなIPSecテクノロジを使用すると、ユーザーはPublic Internetにデータやアプリケーションを公開しなくてすみます。この記事の目的は、OpenswanとLibreswanのIPSec技術を明確にすることです。

Openswanは、Linux用のよく知られたIPSec実装です。今は亡きFreeS/WANプロジェクトのフォークとして始まりましたが、FreeS/WANプロジェクトとは異なり、GNU/Linux OSのみをターゲットにするのではなく、他のOSへもユーザビリティを拡大しました。2012年には、openswanという名前に関する商標の訴訟のため、The Libreswan Projectに改名されました。
Openswan
https://www.openswan.org/
Linux FreeS/WAN
http://www.freeswan.org/
Libreswan VPN software
https://libreswan.org/
その結果、OpenswanパッケージをOracle Linuxにインストールもしくはクエリしようとすると、デフォルトでLibreswanパッケージがインストールされるか、もしくは表示されます。yum search queryコマンドでこの挙動がわかります。
sudo yum search openswan
読み込んだプラグイン:ulninfo
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
============================================================ 一致: openswan ============================================================
NetworkManager-libreswan.x86_64 : NetworkManager VPN plug-in for libreswan
NetworkManager-libreswan-gnome.x86_64 : NetworkManager VPN plugin for libreswan - GNOME files
libreswan.x86_64 : IPsec implementation with IKEv1 and IKEv2 keying protocols
LibreswanはLibreswanプロジェクトがメンテナンスしており、さかのぼることFreeS/WANプロジェクトから、15年以上にわたって活発に開発されています。詳細については、プロジェクトの歴史を参照してください。
History of The Libreswan Project
https://libreswan.org/wiki/History
データを特定の場所からクラウドに移動するための安全な暗号化されたポイントツーポイントチャネルを持つことで、侵害やデータの損失を防ぐ、より安全なソリューションになります。Oracle Cloud Infrastructureと異なるクラウド・プロバイダやオンプレミス環境、またはその両方の間でIPSecのポイント・ツー・ポイント暗号化トンネルを作成する場合は、Libreswanを使用した構成方法を説明する以下のエントリをご覧ください。
Creating a Secure Connection Between Oracle Cloud Infrastructure and Other Cloud Providers
https://blogs.oracle.com/cloud-infrastructure/creating-a-secure-connection-between-oracle-cloud-infrastructure-and-other-cloud-providers