Quantcast
Channel: Oracle Blogs 日本語のまとめ
Viewing all 760 articles
Browse latest View live

[Java] Early Access documentation for Oracle JDK 9 has been updated

$
0
0
原文はこちら。
https://blogs.oracle.com/thejavatutorials/early-access-documentation-for-oracle-jdk-9-has-been-updated

Oracle JDK 9の早期アクセス版のドキュメントが更新されました。
Oracle JDK 9 Documentation Early Access
https://docs.oracle.com/javase/9/
この更新には、以下の内容が含まれています。
JDK 9早期アクセスリリースは以下からダウンロードできます。
JDK 9 Early-Access Builds
http://jdk.java.net/9/

[Java] Using Java Flight Recorder Triggers

$
0
0
原文はこちら。
https://blogs.oracle.com/jtc/using-java-flight-recorder-triggers

Java Flight Recorderや、Java Flight RecorderがOracle Java SE Java VM(JVM)に統合されていて、有効化してもオーバーヘッドが非常に低いことについては、種々のエントリや書籍に記載されています。このツールは、本番環境でのJavaアプリケーションの詳細なランタイム情報を収集するという考え方を可能にするだけでなく、それを実現させるものです。
Java Mission Control
http://www.oracle.com/technetwork/jp/java/javaseproducts/mission-control/java-mission-control-1998576.html
多くの方は、Java Flight Recorderの連続記録モード(Continuous Recording Mode)を使っていますが、この状態では、無期限にランタイムデータを収集します。上書きする前に保持するデータの量を指定できます(またはデフォルト値を使用します)。このモードを使っている場合、いつでも、さまざまなオプションを使用して、ランタイム情報を内蔵のflight recorderファイルにダンプすることができます。その後、Java Mission Controlを使用してこのファイルを開き、実行中のアプリケーションの挙動をさらに診断することができます。
Java Platform, Standard Edition
Java Mission Controlユーザーズ・ガイド リリース5.5
http://docs.oracle.com/javacomponents/jp/jmc-5-5/jmc-user-guide/toc.htm
Java Mission Control User's Guide Release 5.5
https://docs.oracle.com/javacomponents/jmc-5-5/jmc-user-guide/toc.htm
Flight Recorderダンプをランダムまたは定期的に取得するのではなく、条件付きでダンプを取得することもできます。具体的には、トリガーを使用しつつ、定義済み条件を満たす場合にフライトレコーダーのダンプを発生させるルールを作成できます。このシナリオでは、状況が悪化しはじめた場合に、ずっと大量のデータセットを見るのではなく、トリガーによってランタイム情報の詳細に集中できるという点で役に立つことが想像できます。以下の動画では、簡単な説明後、Flight Recorderのダンプをトリガーを使って取得する方法を説明しています。その後、Mission Controlを使って、ダンプされたFlight Recorderのファイルを読み込み、サンプルアプリケーションの動作を診断しています。

[Cloud] Kubernetes Community Engagement: Time to Roll!

$
0
0
原文はこちら。
https://blogs.oracle.com/developers/kubernetes-community-engagement-time-to-roll

原文はT.J. Fontaine @tjfontaine)によるものです。

CoreOS Fest 2017に参加できることを光栄に思っています。この機会を使って重要な取り組み2件をお知らせします。
CoreOS Fest 2017
https://coreos.com/fest/
Kubernetesプロジェクトへの参加のため、エンジニアリング・リソースを捧げることにしています。
Kubernetes - Production-Grade Container Orchestration
https://kubernetes.io/
Kubernetesは、分散システムを展開するためのオーケストレーション・プラットフォームの1つで、成熟度と方向性を考えれば、Oracleは大きな貢献をしていると確信しています。
また、CoreOSと連携し、CoreOS Container LinuxをOracle Cloud Infrastructureに導入しています。
CoreOS
https://coreos.com/
Oracle Cloud Infrastructure as a Service
https://cloud.oracle.com/ja_JP/iaas
最先端の最適化されたLinux OSと業界で最も包括的な高性能クラウドプラットフォームを組み合わさることで、開発者は、CoreOS Container Linuxのパフォーマンスやセキュリティ機能をエンタープライズ・ワークロードに活用できるようになります。
Why CoreOS
http://coreos.com/why/
Oracleは、我々の新しいクラウドサービスの展開、運用のために何よりもまずKubernetesに投資しています。現実世界の経験をアクションに移しているので、Kubernetesの運用に対する我々の理解が、コミュニティにとっての価値あるものになると考えています。
今後数週間は、コミュニティチャンネルに参加することから始めて、段階的に取り組んでいきます。コミュニティの成功を支援することが、Oracleを含むすべての人のためにKubernetesを改善につながると理解しています。そこで私たちは、Kubernetesを改善し、SlackやStackOverflow、およびGitHubのIssueにある質問に答えることでコミュニティを支援するという私たちのコミットメントを示します。
Kubernetes on Slack
http://slack.k8s.io/
StackOverflow (Tagged Kubernetes)
https://stackoverflow.com/questions/tagged/kubernetes
GitHub
https://github.com/kubernetes/kubernetes
オープンソースへの参加には透明性が求められるため、Kubernetesおよびそのエコシステムに取り入れた作業の全ては以下のGitHubでご覧いただけるようにします。
https://github.com/oracle
我々はコミュニティおよびメンテナーと密接に協力し、コミュニティ全体に最大の影響を与える問題や機能に取り組んでいきます。

Related content:

私たちのチームは、伝統的なエンタープライズソフトウェアベンダー出身者からクラウドネイティブの新興企業出身者といった多様な背景を持つ面々だけでなく、世界的に展開されるサービスを提供してきた経歴を持つ人々から成り立っています。 私たちの専門知識を踏まえれば、Federation、Security、ServerlessなどといったSIG(Special Interest Group)にかなり参加できると考えています。こうしたコミュニティへの参加は、コミュニティのニーズを満たす新機能の同意を進めるだけでなく、製品を改良する上でも有用と考えています。
当社はKubernetesを使ってサービスを提供しようとしており、現在Oracle Cloud Infrastructureのファースト・クラス体験を提供するプラグインを開発しています。既にKubernetesをお使いで、Oracle Cloudを試してみたいのであれば、自然なことに感じるはずです。
私たちはこの活気のあるコミュニティに参加できてわくわくしています。私たちが一緒に作るものを目の当たりにしたくてたまりません。
是非ご期待ください。

著者について
TJ Fontaineは、高可用性を持つクラウドネイティブなコンテナ化されたサービスのアーキテクチャ設計やデリバリを担当するOracleのソフトウェアエンジニアで、またNode.js、Linux、Monoといったオープンソースのベテランコントリビュータ-でもあります。Node.jsのProject Leadをつとめつつ、コミュニティの拡大ならびにエンタープライズでの採用を進めてきました。BDFLモデルからNode.js Foundationへの移行も支援しました。

[Cloud] Automating Processes With Application Builder and Process Cloud Services

$
0
0
原文はこちら。
https://blogs.oracle.com/shay/automating-processes-with-application-builder-and-process-cloud-services

Oracle Application Builder Cloud Service (ABCS) を使うと、データを追跡するアプリケーションを開発することができますが、そのデータがプロセスに関わっているとしたらどうでしょうか。データ収集だけでなく、人間のワークフローのやりとりを自動化する必要がある場合はどうすればよいでしょうか?Oracle ABCSとOracle Process Cloud Service(PCS)が今回統合されたことにより、こうした課題を簡単に実現できます。
Oracle Process Cloud Service
https://cloud.oracle.com/ja_JP/process
ABCSビジネス・オブジェクトと関連するプロセスを作成し、直接Oracle ABCSのUIから対話することができます。これは双方向Interaction Patternで、PCSのプロセスがOracle ABCSビジネス・オブジェクトから情報を取得し、ABCS UIをPCSプロセス上に作成してプロセスの開始、進行が可能です。

以下の動画は、基本的な出張申請承認フローを開発する例で、以下の内容を含む統合方法を紹介しています。
  • ビジネス・オブジェクトとプロセスの関連付け
  • プロセスからビジネス・オブジェクトの値へのアクセス
  • PCSとABCS間のセキュリティおよび接続の設定
  • ABCSのページからPCSプロセスの起動
  • タスクを表示するためのカスタムToDoリストページをABCSで作成
  • タスクを進めるためのカスタムタスク詳細ページをABCSで作成
ご覧になるとわかる通り、これらの全てが非常にシンプルかつ完全に宣言的に、ビジュアル開発アプローチで達成しています。

製品の組み合わせによって、PCSならびにABCSのユーザーに対しすばらしい価値を提供します。PCSをご利用のお客様には、プロセスで利用するデータを永続化する機能やずっと抱負な機能のUIやレポートのデザインが可能な点が気に入って頂けるかと思います。ABCSをご利用のお客様は、長時間実行する複雑なプロセスの自動化および管理が可能になる点が気に入って頂けるのではないでしょうか。

[Java] Java EE 8 - May recap

$
0
0
原文はこちら。
https://blogs.oracle.com/theaquarium/java-ee-8-may-recap

直近のJava EE 8アップデートをまとめておきます。
5月は、JSON-P 1.1 (JSR 374) 、CDI 2.0 (JSR 365) がそれぞれのFinal Approval Ballotを通過しました。
JSR 374: JavaTM API for JSON Processing 1.1
https://jcp.org/en/jsr/detail?id=374
Final Approval Ballot
https://jcp.org/en/jsr/results?id=5982
JSR 365: Contexts and Dependency Injection for JavaTM 2.0CDI 2.0 (JSR 365)
https://jcp.org/en/jsr/detail?id=365
Final Approval Ballot
https://jcp.org/en/jsr/results?id=5995
Java EEプラットフォーム全体におけるCDIの重要性を考慮すれば、これはJava EE 8の重要なマイルストンです。是非以下のエントリをチェックしてください。
Tour around Weld 3
http://weld.cdi-spec.org/news/2017/05/19/tour-around-weld-3/
先月、JSON-B (JSR 367) はFinal Approval Ballotの期間に入りました。この間、JSON-Bの参照実装であるYassonを以下のURLから入手できます。
JSR 367: JavaTM API for JSON Binding (JSON-B)
https://jcp.org/en/jsr/detail?id=367
Yasson 1.0.0-M2
https://repo.eclipse.org/content/repositories/yasson-releases/org/eclipse/yasson/1.0.0-M2/
Servlet 4.0 (JSR 369)、JAX-RS 2.1 (JSR 370)、Bean Validation 2.0 (JSR 380) はいずれも5月にPublic Reciewを終え、現在Public Review Ballotの期間に入っています。さらに、それぞれのSpec LeadがJSRのステータスアップデートをJCP Executive Committeeに提示しました。
最後に、Java EE 8 (JSR 366) 自体もまたPublic Review Ballotの期間に入りました。
JSR 366: Java Platform, Enterprise Edition 8 (Java EE 8) Specification
https://jcp.org/en/jsr/detail?id=366
Java EE Security API (JSR 375) は現在Public Reviewの期間にあります。これはこの新しいAPIにとって明らかに重要なステップです。
JSR 375: JavaTM EE Security API
https://jcp.org/en/jsr/detail?id=375
JSR-000375 JavaTM EE Security API 1.0 Public Review:
https://jcp.org/aboutJava/communityprocess/pr/jsr375/index.html
Java EE 8に向けてメンテナンスリリースを実施しているさまざまな仕様の進捗状況も確認されています。
全体として、種々のJava EE 8仕様の最終化に向け、着実に進捗していることがわかります。先月はGlassFish 5 Promoted Buildを2個リリースしました。Java.netが廃止された後の最初のビルドであるということで、スコープが比較的制限されています。
GlassFish 5 Promoted Build 6
https://blogs.oracle.com/theaquarium/glassfish-5-promoted-build-6
https://orablogs-jp.blogspot.jp/2017/05/glassfish-5-promoted-build-6.html
GlassFish 5 Promoted Build 7
https://blogs.oracle.com/theaquarium/glassfish-5-promoted-build-7
https://orablogs-jp.blogspot.jp/2017/05/glassfish-5-promoted-build-7.html
新しいGlassFishのビルドパイプラインに対して多くの作業を実施し、ほぼ終了しています。そのため、今後数週間でGlassFish 5の進捗が加速すると期待されます。フロントの基盤についてまとめるにあたり、すべてのJava EE関連のディスカッションが新しいプラットフォームjavaee.groups.ioでホストされていることに言及しておかねばならないでしょう。
javaee@javaee.groups.io
https://javaee.groups.io/
まだ参加されていない場合には、是非ディスカッションに参加してください。

[Cloud] Accessing Oracle Process Cloud Service REST API using OAuth

$
0
0
原文はこちら。
https://community.oracle.com/community/cloud_computing/oracle-cloud-developer-solutions/blog/2017/02/19/accessing-oracle-process-cloud-service-rest-api-using-oauth

Oracle Process Cloud service (PCS) はREST APIを提供しており、これを使って他のアプリケーションをPCSと統合できます。REST APIの詳細はリファレンスを参照ください。
REST API for Oracle Process Cloud Service, Version 4.0
https://docs.oracle.com/en/cloud/paas/process-cloud/cprrb/index.html
Oracle Process Cloud ServiceのREST APIは基本認証だけでなく、OAuthトークンを利用することもできます。このエントリでは、OAuthトークンを使ってPCSのREST APIにアクセスし、プロセスの新規インスタンスを作成する方法をご紹介します。

このエントリで説明するシナリオは、JCS-SXにデプロイ済みのWebアプリケーションが、PCSにデプロイ済みのビジネスプロセス("Funds Transfer Process") を呼び出すというものです。この"Funds Transfer"プロセスは、シンプルなプロセスで、リクエストメッセージに含まれるある属性を検証し、必要に応じて人による承認へと進めるものです。このWebアプリケーションはOAuthサーバからOAuthトークンを取得し、トークンを認証のためにPCS REST APIに渡します。

下図はJCS-SX、PCS、OAuthサーバ間のやりとりの概要を図示したものです。

このユースケースでは、JCS-SXインスタンスとPCSインスタンスがともに同じアイデンティティドメインでプロビジョニングされている前提です。同一アイデンティティドメインでプロビジョニングされる場合、OAuthを使った通信に必要なリソースやクライアントはトークン取得のために利用するOAuthサーバと一緒に自動的に構成されます。マイサービス(My Services)のOAuth管理(OAuth Administration)タブを開き、以下のOAuthリソースおよびデフォルトで登録済みのクライアントを確認できます。詳細は以下のURLをご覧ください。
Oracle® Cloud Administering Oracle Cloud Identity Management Release 17.2
Managing OAuth Resources and Clients
https://docs.oracle.com/en/cloud/get-started/subscriptions-cloud/csimg/managing-oauth-resources-and-clients.html
Note: OAuth管理にアクセスするためには、アイデンティティドメイン管理者ロールが必要です。


Note: クライアント識別子(Id、上図の赤枠で囲んだ部分)および、JCS-SX OAuthクライアントの[機密の表示](Show Secret)をクリックすると確認可能なIdに対応する機密 (secret) は、Webアプリケーションがクライアントのアクセストークン取得ならびにPCS REST APIのアクセスするために利用します。

JCS-SX OAuthクライアントを使って、PCS REST APIをWebアプリケーションから呼び出すため、PCSリソースがクライアントからアクセス可能であることを確認しておきましょう。リソースへのアクセス可否は、[クライアントの登録]セクションのJCS-SX OAuthクライアントで、アクションパレット内の変更(Modify)メニューをクリックすることで管理できます(下図)。
pcs_oauth_blog_image_2.png

Note: このエントリでは、ビジネスプロセス(Funds Transfer Process)をPCSにデプロイされていることを前提とします。参考のためにAppendixセクションにこのビジネスプロセスのエクスポート・アーカイブがあります。

前提条件が整えば、WebアプリケーションがPCS REST APIを呼び出すために使うクライアントアクセストークンの取得に取りかかることができます。このサンプルでは、OAuthグラントタイプ(クライアント資格証明とパスワード)を使い、以下の手順でクライアントアクセストークンを取得します。
  1. クライアント資格証明を使ってクライアントアサーションを取得
  2. 取得したクライアントアサーションを使ってアクセストークンを取得
Note: Oracle Platform Service内でWebサービスを呼び出す場合、OWSMポリシーを使えばID伝播を実現でき、明示的にOAuthトークンを処理する必要はありません。今回はOAuthトークンを使ってPCSで認証するための説明を目的としているため、OWSMポリシーを使いません。

これらの手順を具体的なコード・スニペットを使って詳細に説明します。

呼び出し対象のビジネスプロセスの詳細情報と、OAuthトークンサーバへアクセスするために必要な詳細情報をHashMapに保存します。

Note: 説明の都合上、クライアント機密、ユーザー名、パスワードはjava.HashMapに格納していますが、資格証明の安全な管理を確実にするためには、Oracle Credential Store Framework (CSF) の利用を強く推奨します。文末のReferencesセクションから詳細情報を確認してください。
public static HashMap populateMap() {  
HashMap map = new HashMap();
// PCS
map.put("PCS_URL", "https://<PCS_HOST>:443/bpm/api/3.0/processes");
map.put("PCS_PROCESS_DEF_ID", "default~MyApplication!1.0~FundsTransferProcess");
map.put("PCS_FTS_SVC_NAME", "FundsTransferProcess.service");
// OAuth
map.put("TOKEN_URL", "https://<ID_DOMAIN_NAME>.identity.<DATA_CENTER>.oraclecloud.com/oam/oauth2/tokens");
map.put("CLIENT_ID", "<CLIENT_ID>");
map.put("SECRET", "<SECRET>");
map.put("DOMAIN_NAME", "<ID_DOMAIN_NAME>");
map.put("USER_NAME","<PCS_USER_NAME>");
map.put("PASSWORD","<PCS_USER_PWD>");
return map;
}

public String getOAuthToken() throws Exception {
String token = "";
String authString = entryMap.get("CLIENT_ID")+":"+entryMap.get("SECRET");

Map clientAssertionMap = getClientAssertion(authString);
token = getAccessToken(authString,clientAssertionMap);

return token;
}
Note: 上記コードで指定した、PCS_PROCESS_DEF_IDおよび PCS_FTS_SVC_NAME をキーとする値は参考のためです。PCSにfunds transferビジネスプロセスをデプロイした後、以下のcURLコマンドを実行してビジネスプロセスの詳細を取得できます。取得した値を使って置き換えてください。
curl -u <PCS_USER_NAME>:<PCS_USER_PWD> -H "Content-Type:application/json" -H "Accept:application/json" -X GET https://<PCS_HOST>:443/bpm/api/4.0/process-definitions
getOAuthTokenメソッドは、OAuthサーバ(トークンエンドポイント)へアクセスし基本認証ヘッダとしてclient_id:client_secret を渡すことで、クライアントアサーションを取得するための実装です。これらの詳細情報は、前述のOAuth管理タブから取得できます。以下のコードスニペットはその実装例です。
(訳注)
原文ではJerseyに依存するコードを使っていますが、JAX-RS 2.0ベースに書き換えています。
private Map<String, String> getClientAssertion(String authString) throws Exception {

    MultivaluedHashMap<String, String> formData = new MultivaluedHashMap();
    formData.putSingle("grant_type", "client_credentials");

    Response response
         = ClientBuilder.newClient()
                        .target(entryMap.get("TOKEN_URL").toString())
                        .request()
                        .header(HttpHeaders.AUTHORIZATION, "Basic " + DatatypeConverter.printBase64Binary(authString.getBytes("UTF-8")))
                        .header(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=UTF-8")
                        .buildPost(Entity.entity(formData,
                                                 MediaType.APPLICATION_FORM_URLENCODED_TYPE))
                        .invoke();
    if (response.getStatus() != Response.Status.OK.getStatusCode()) {
        throw new Exception(response.getStatusInfo().getReasonPhrase());
    }

    Map<String, String> assertionMap = new HashMap<>();
    try (JsonReader reader = Json.createReader(new StringReader(response.readEntity(String.class)))) {
        response.close();
        JsonObject jsonObj = reader.readObject();
        assertionMap.put("assertion_token", jsonObj.get("access_token").toString());
        assertionMap.put("assertion_type", jsonObj.get("oracle_client_assertion_type").toString());
    }
    return assertionMap;
}
上記のコードでは、Jerseyクライアントを使ってトークンサーバにアクセスし、クライアントアサーションとクライアントアサーションタイプを取得するとともに、ペイロード内でgrant_type:client_credentialsも渡しています。以下のコードスニペットでは、password grant_typeを使い、ユーザー名とパスワードを先ほど取得したクライアントアサーションとともに渡すことで、クライアントアクセストークンをトークンサーバから取得しています。
private String getAccessToken(Map clientAssertionMap) throws Exception {

    MultivaluedHashMap<String, String> formData = new MultivaluedHashMap();
    formData.putSingle("grant_type", "password");
    formData.putSingle("username", entryMap.get("USER_NAME").toString());
    formData.putSingle("password", entryMap.get("PASSWORD").toString());
    formData.putSingle("client_assertion_type", clientAssertionMap.get("assertion_type").toString());
    formData.putSingle("client_assertion", clientAssertionMap.get("assertion_token").toString());

    Response response =
        ClientBuilder.newClient()
                     .target(entryMap.get("TOKEN_URL").toString())
                     .request()
                     .header(HttpHeaders.AUTHORIZATION, "Basic " + DatatypeConverter.printBase64Binary(authString.getBytes("UTF-8")))
                     .header(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=UTF-8")
                     .buildPost(Entity.entity(formData, MediaType.APPLICATION_FORM_URLENCODED_TYPE))
                     .invoke(Response.class);

    if (response == null || response.getStatus() != Response.Status.OK.getStatusCode()) {
        throw new Exception(response.getStatusInfo().getReasonPhrase());
    }

    String accessToken;
    try (JsonReader reader = Json.createReader(new StringReader(response.readEntity(String.class)))) {
        response.close();
        JsonObject jsonObj = reader.readObject();
        accessToken = jsonObj.getString("access_token");
    }
    return accessToken;
}
これでクライアントアクセストークンを使ってPCSリソースにアクセスできるようになりました。以下のコードスニペットは、PCS REST APIを呼び出し、Funds Transferビジネスプロセスの新規プロセスインスタンスを生成しようとしています。ペイロードには、インスタンス作成対象のプロセス情報(定義ID、サービス名など)と、JSPページでユーザーが入力した入力パラメータが含まれています。先ほどの手順で取得したOAuthトークンをAuthorizationヘッダーに設定していることに注意してください。
public String invokeFundsTransferProcess(String token, FundsTransferRequest ftr) throws Exception {

    JsonObject postObj =
        Json.createObjectBuilder()
            .add("processDefId", entryMap.get("PCS_PROCESS_DEF_ID").toString())
            .add("serviceName", entryMap.get("PCS_FTS_SVC_NAME").toString())
            .add("operation", "start")
            .add("action", "Submit")
            .add("params",
                Json.createObjectBuilder()
                    .add("incidentId", ftr.getIncidentId())
                    .add("sourceAcctNo", ftr.getSourceAcctNo())
                    .add("destAcctNo", ftr.getDestAcctNo())
                    .add("amount", ftr.getAmount())
                    .add("transferType",
                            ftr.getTransferType()
                            .equals("tparty") ? "intra" : "inter"))
            .build();

    Response response =
        ClientBuilder.newClient()
                     .target(entryMap.get("PCS_URL").toString())
                     .request(MediaType.APPLICATION_JSON_TYPE)
                     .header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
                     .buildPost(Entity.entity( postObj.toString(),
                                               MediaType.APPLICATION_JSON_TYPE))
                     .invoke(Response.class);

    if (response != null && response.getStatus() != Response.Status.OK.getStatusCode()) {
        throw new Exception(response.getStatusInfo().getReasonPhrase());
    }
    return String.valueOf(response.getStatus());
}
シンプルなJSPページを使ってユーザー入力を捕捉し、Funds Transferビジネスプロセスを起動します。

Funds Transferプロセスを開始出来た場合、下図のように、PCSのTrackingページで、生成済みかつ実行中のプロセスインスタンスを確認できます。



Known Issues:

ご利用のJDKによっては、PCS REST APIをJCS-SXから呼び出した場合に「javax.net.ssl.SSLHandshakeException: server certificate change is restricted during renegotiation」というエラーが出る可能性があります。その場合には、回避策として、JCS-SXの以下のシステムプロパティを設定して、サーバーを再起動してください。
  1. weblogic.security.SSL.minimumProtocolVersion をJCS-SXで TLSv1.2 に設定し、再起動する
  2. まだ問題が解決しない場合、jdk.tls.allowunsafeservercertchange を true に設定し、JCS-SXを再起動する

Appendix:

Funds Transferビジネスプロセス(PCSからエクスポートしたアプリケーション:MyApplication.zip

References:

[Cloud] Java EE based microservice on Oracle Cloud with Payara Micro

$
0
0
原文はこちら。
https://community.oracle.com/community/cloud_computing/oracle-cloud-developer-solutions/blog/2017/03/09/java-ee-based-microservice-on-application-container-cloud-with-payara-micro

このエントリでは、Payara Microを使って、Java EEベースのマイクロサービスを構築する方法をご紹介します。
Payara Micro
http://www.payara.fish/payara_micro
Oracle Cloud (PaaS) Stackの以下のサービスを活用します。
  • Developer Cloud service
    コードのホスト(Git Repository)、および(他のOracle PaaSサービスとの統合による) Continuous Integration & Continuous Deployment機能の提供 
  • Application Container Cloud service
    Java EE マイクロサービスを実行するためのスケーラブルなaPaaS

Overview

Payara Micro?

Payara Microとは、マイクロサービススタイルのアプリケーションを構築するためのJava EEベースのソリューションです。少々説明しますと・・・
  • Java EE
    Payara MicroはJava EE Web Profile標準ならびにWeb Profileに含まれないその他の仕様(例えばBatch、Concurrency Utilitiesなど)もサポートします。
  • It’s a library
    これらの機能は全てカプセル化されたJARファイルとして利用できます。

Development model

Payara Microは複数のデプロイメントスタイルを選択できます。
  • WAR
    Java EEアプリケーションをWARファイルにパッケージし、以下のかたちでPayara Microとともに起動します。
    java –jar payara-micro-<version>.jar --deploy mystocks.war
  • Embedded mode
    ライブラリあので、Javaアプリケーション内にAPIを使って埋め込むことができます。
  • Uber JAR
    Payara MicroはMavenをサポートしているので、 exec pluginを使い、fat JARとしてPayara MicroライブラリとともにWARファイルをパッケージします。
    exec:javaプラグイン
    http://www.mojohaus.org/exec-maven-plugin/java-mojo.html
このエントリでは、fat JARの方法を使うことにします。

Benefits

潜在的なメリットは以下のようです。
  • Microservices friendly
    ライブラリとしてJava EEを使えるため、アプリケーション内で簡単に利用でき、柔軟な方法(WAR+JAR、もしくはただのfat JAR)でパッケージできます。また、PaaS、コンテナベースのプラットフォームといった複数の環境で実行できます。
  • Leverage Java EE skill set
    JAX-RS、JPA、EJB、CDIといったJava EE仕様の知識を活用できます。

About the sample application

JAX-RSやEJB、CDI、WebSocketといったAPIを使うシンプルなJava EEアプリケーションです。これはNYSEの仮株券の株価の追跡に役立つアプリケーションです。
  • 利用者はNASDAQに上場している株価をシンプルなRESTインターフェースでチェックできます。
  • リアルタイムの株価追跡も可能ですが、この機能はOracle (ORCL) に対してのみ有効です。
ハイレベル図と背景をまとめておきます。
  • EJBスケジューラがORCLを定期的にチェックして株価を取得し、CDIイベントを発行します。(CDI Event Observerとしてマークされた)WebSocketコンポーネントがそのイベントを受け取り、接続済みのクライアントに対し最新の価格をアップデートします。
  • JAX-RS RESTエンドポイントを使ってオンデマンドで任意の企業の株価を取得します。これは(双方向、完全二重型のWebSocketインタラクションとは異なる)典型的なリクエスト-レスポンスベースのHTTPインタラクションです。 

Code

では、関連する部分のコードを見ていきましょう(簡単にするためにimport文は省略しています)。

RealTimeStockTicker.java
@ServerEndpoint("/rt/stocks") 
public class RealTimeStockTicker {


//stores Session (s) a.k.a connected clients
private static final List<Session> CLIENTS = new ArrayList<>();

/**
* Connection callback method. Stores connected client info
*
* @param s WebSocket session
*/
@OnOpen
public void open(Session s) {
CLIENTS.add(s);
Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Client connected -- {0}", s.getId());
}

/**
* pushes stock prices asynchronously to ALL connected clients
*
* @param tickTock the stock price
*/
public void broadcast(@Observes @StockDataEventQualifier String tickTock) {
Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Event for Price {0}", tickTock);
for (final Session s : CLIENTS) {
if (s != null && s.isOpen()) {
/**
* Asynchronous push
*/
s.getAsyncRemote().sendText(tickTock, new SendHandler() {
@Override
public void onResult(SendResult result) {
if (result.isOK()) {
Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Price sent to client {0}", s.getId());
} else {
Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.SEVERE, "Could not send price update to client " + s.getId(),
result.getException());
}
}
});
}
}
}

/**
* Disconnection callback. Removes client (Session object) from internal
* data store
*
* @param s WebSocket session
*/
@OnClose
public void close(Session s) {
CLIENTS.remove(s);
Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Client discconnected -- {0}", s.getId());
}
}
StockDataEventQualifier.java
/**
* Custom CDI qualifier to stamp CDI stock price CDI events
*
*/
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface StockDataEventQualifier {
}
StockPriceScheduler.java
/** 
* Periodically polls the Google Finance REST endpoint using the JAX-RS client
* API to pull stock prices and pushes them to connected WebSocket clients using
* CDI events
*
*/
@Singleton
@Startup
public class StockPriceScheduler {


@Resource
private TimerService ts;
private Timer timer;


/**
* Sets up the EJB timer (polling job)
*/
@PostConstruct
public void init() {
/**
* fires 5 secs after creation
* interval = 5 secs
* non-persistent
* no-additional (custom) info
*/
timer = ts.createIntervalTimer(5000, 5000, new TimerConfig(null, false)); //trigger every 5 seconds
Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "Timer initiated");
}


@Inject
@StockDataEventQualifier
private Event<String> msgEvent;


/**
* Implements the logic. Invoked by the container as per scheduled
*
* @param timer the EJB Timer object
*/
@Timeout
public void timeout(Timer timer) {
Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "Timer fired at {0}", new Date());
/**
* Invoked asynchronously
*/
Future<String> tickFuture = ClientBuilder.newClient().
target("https://www.google.com/finance/info?q=NASDAQ:ORCL").
request().buildGet().submit(String.class);


/**
* Extracting result immediately with a timeout (3 seconds) limit. This
* is a workaround since we cannot impose timeouts for synchronous
* invocations
*/
String tick = null;
try {
tick = tickFuture.get(3, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "GET timed out. Next iteration due on - {0}", timer.getNextTimeout());
return;
}

if (tick != null) {
/**
* cleaning the JSON payload
*/
tick = tick.replace("// [", "");
tick = tick.replace("]", "");


msgEvent.fire(StockDataParser.parse(tick));
}


}


/**
* purges the timer
*/
@PreDestroy
public void close() {
timer.cancel();
Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "Application shutting down. Timer will be purged");
}
}
RESTConfig.java
/**
* JAX-RS configuration class
*
*/
@ApplicationPath("api")
public class RESTConfig extends Application{

}
StockDataParser.java
/**
* A simple utility class which leverages the JSON Processing (JSON-P) API to filter the JSON
* payload obtained from the Google Finance REST endpoint and returns useful data in a custom format
*
*/
public class StockDataParser {

public static String parse(String data){

JsonReader reader = Json.createReader(new StringReader(data));
JsonObject priceJsonObj = reader.readObject();
String name = priceJsonObj.getJsonString("t").getString();
String price = priceJsonObj.getJsonString("l_cur").getString();
String time = priceJsonObj.getJsonString("lt_dts").getString();

return (String.format("Price for %s on %s = %s USD", name, time, price));
}
}

A note on packaging

開発の観点から、前述の通り、通常のWARベースのJava EEアプリケーションをfat JARとしてPayara Microのコンテナとともにパッケージします。

コンテナにアプリケーションをデプロイするのではなく、アプリケーションとともにコンテナをパッケージングする点にご注意ください。

Payara MicroライブラリにJava EE APIは存在するので、Java EE APIはコンパイル時のみ必要です(scope = provided)
<dependency> 
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
Mavenプラグインを使ってfat JARを生成します
<plugin> 
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<dependencies>
<dependency>
<groupId>fish.payara.extras</groupId>
<artifactId>payara-micro</artifactId>
<version>4.1.1.164</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>payara-uber-jar</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>fish.payara.micro.PayaraMicro</mainClass>
<arguments>
<argument>--deploy</argument>
<argument>${basedir}/target/${project.build.finalName}.war</argument>
<argument>--outputUberJar</argument>
<argument>${basedir}/target/${project.build.finalName}.jar</argument>
</arguments>
<includeProjectDependencies>false</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
<executableDependency>
<groupId>fish.payara.extras</groupId>
<artifactId>payara-micro</artifactId>
</executableDependency>
</configuration>
</execution>
</executions>
</plugin>

Setting up Continuous Integration & Deployment

以下の章でOracle Developer Cloud Serviceで実施した構成について取り扱います。

Project & code repository creation

以下のエントリのProject & code repository creationの章をご覧になるか、詳細についてはサービスのドキュメントをご覧ください。
Tracking JUnit test results in Developer Cloud service
https://community.oracle.com/community/cloud_computing/oracle-cloud-developer-solutions/blog/2016/10/05/junit-testing-using-oracle-developer-cloud
Oracle® Cloud Using Oracle Developer Cloud Service
Creating a Project
http://docs.oracle.com/cloud/latest/devcs_common/CSDCS/GUID-3317B279-A9C0-4566-A289-BD651A89D7B5.htm#GUID-7B30C8EC-6CDA-4F14-9791-8AE3BB3E8343

Configure source code in Git repository

ローカルシステムから先ほど作成したDeveloper CloudのGitリポジトリにプロジェクトをPushします。
Oracle® Cloud Using Oracle Developer Cloud Service
Pushing an Existing Local Git Repository to an Empty Oracle Developer Cloud Service Git Repository
http://docs.oracle.com/cloud/latest/devcs_common/CSDCS/GUID-B4C03296-8497-4356-8C74-2031D1FB96FC.htm#CSDCS-GUID-A33E83CE-845C-4393-8C93-936527033715
この操作はコマンドラインから実施しますが、事前にGitクライアントをローカルマシンにインストールしておく必要があります。Gitを使ってもいいですし、お好みのものを使うことができます。
Git
https://git-scm.com/downloads
cd <project_folder>  
git init
git remote add origin <developer_cloud_git_repo>
//e.g. https://john.doe@developer.us.oraclecloud.com/developer007-foodomain/s/developer007-foodomain-project_2009/scm/sample.git//john.doe@developer.us.oraclecloud.com/developer007-foodomain/s/developer007-foodomain-project_2009/scm/sample.git
git add .
git commit -m "first commit"
git push -u origin master //Please enter the password for your Oracle Developer Cloud account when prompted

Configure build

新しいジョブを作成しましょう。


JDKを選択します。


Continuous Integration (CI)

Git リポジトリを選択します。


ビルドトリガーを設定します。このビルドジョブは、(git pushなどの)Gitリポジトリの更新に応じて呼び出されます。


ビルドステップを追加します。
  • Maven : WARとfat JAR作成のためのビルドステップ
  • Execute Shell : 必要なデプロイメント・ディスクリプタ(Application Container Cloudではmanifest.jsonが必要です)とともにアプリケーションJARをパッケージングするステップ


以下はコマンドの例です。
zip -j accs-payara-micro.zip target/mystocks.jar manifest.json  
manifest.json の例です。
{ 
"runtime": {
"majorVersion": "8"
},
"command": "java -jar mystocks.jar --port $PORT --noCluster",
"release": {
"build": "23022017.1202",
"commit": "007",
"version": "0.0.1"
},
"notes": "Java EE on ACC with Payara Micro"
}
デプロイ可能なZipファイルをアーカイブするためのビルド後のアクションを有効化します。


Execute Build

デプロイメントの構成前に、デプロイメントの構成が参照可能なアーティファクトを生成するためにビルドを呼び出す必要があります。


ビルドが完了した後、以下のことが可能になっています。
  • ビルドログの確認
  • アーカイブ済みのアーティファクトの確認
ログ


アーティファクト


Continuous Deployment (CD) to Application Container Cloud

新たにデプロイメント用のConfigurationを作成します。


  • 必要事項を入力し、Deployment targetを構成します
  • Application Container Cloudインスタンスを構成します
  • 最後の確認ページの自動デプロイメントオプションを構成します
最終的に以下のような構成になっているはずです。


確認画面


Application Container Cloudのアプリケーションを確認します。


Test the CI/CD flow

ちょっとコードを変更し、Developer Cloud ServiceのGitリポジトリにPushしてみましょう。すると以下を確認できるはずです。
  • 自動的にビルドが呼び出され、成功したら
  • 自動的にデプロイメントプロセスが呼び出され
  • つづいて新しいバージョンのアプリケーションをApplication Container Cloudに再デプロイする

Test the application

  • 特定の企業の株価をチェックする場合、GETでURLをつつきます。以下はその例です(このURLはサンプルで、実際にデプロイした環境にあわせる必要があります)。
    https://acc-p-m-mydomain.apaas.em1.oraclecloud.com/mystocks/api/stocks?ticker=AAPL
  • リアルタイムフィードをサブスクライブする場合、WebSocketクライアントを使って指定のエンドポイントURLにアクセスします。以下はその例です。
    wss://acc-p-m-mydomain.apaas.em1.oraclecloud.com/mystocks/rrt/stocks
Chomeブラウザにプラグインとしてインストールできるクライアントを使うことをお勧めします。例えば、Simple WebSocket Clientなどがよいでしょう。
Simple WebSocket Client
https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo?hl=en

[Docker, Cloud, Java] Dynamic load balancing for Docker based JavaEE microservices on Oracle Container Cloud

$
0
0
原文はこちら。
https://community.oracle.com/community/cloud_computing/oracle-cloud-developer-solutions/blog/2017/04/04/dynamic-load-balancing-for-docker-based-javaee-microservices-on-oracle-container-cloud

このエントリではDockerベースのJava EEマイクロサービスをHAProxyを使ってHA/負荷分散モードで実行する方法をご紹介します。全てOracle Container Cloud上で実行します。
HAProxy - The Reliable, High Performance TCP/HTTP Load Balancer
http://www.haproxy.org/
Oracle Container Cloud Service
https://cloud.oracle.com/ja_JP/container
簡単に概要をご紹介します。
  • WildFly Swarmを使うJava EEマイクロサービス
    シンプルなJAX-RSベースのRESTアプリケーション
  • HAProxy
    アプリケーションの複数インスタンスへの負荷分散に利用
  • Docker
    個々のコンポーネント、つまりマイクロサービスおよび負荷分散サービスをDockerイメージにパッケージング
  • Oracle Container Cloud
    Oracle Container Cloud上でサービスを構成し、スケーラブルかつ負荷分散しながらサービスを実行します。

Application

このアプリケーションは、株価を取得する非常にシンプルなJAX-RSを使うREST APIです。
@GET 
public String getQuote(@QueryParam("ticker") final String ticker) {


    Response response = ClientBuilder.newClient().
            target("https://www.google.com/finance/info?q=NASDAQ:" + ticker).
            request().get();


    if (response.getStatus() != 200) {
        //throw new WebApplicationException(Response.Status.NOT_FOUND);
        return String.format("Could not find price for ticker %s", ticker);
    }
    String tick = response.readEntity(String.class);
    tick = tick.replace("// [", "");
    tick = tick.replace("]", "");


    return StockDataParser.parse(tick)+ " from "+ System.getenv("OCCS_CONTAINER_NAME");
}  
WildFly Swarmは単なるJava EEランタイムとして利用しています。シンプルなWARベースのJava EEプロジェクトを作成し、Swarm Mavenプラグインを使って、必要なパーツを自動的に検出して構成し、WARからfat JARを作成するという、"魔法"を織り込みます。
WildFly Swarm
http://wildfly-swarm.io/
<build> 
    <finalName>occ-haproxy</finalName>
    <plugins>
         
        <plugin>
            <groupId>org.wildfly.swarm</groupId>
            <artifactId>wildfly-swarm-plugin</artifactId>
            <version>1.0.0.Final</version>
            <executions>
                <execution>
                    <goals>
                        <goal>package</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
 
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <compilerArguments>
                    <endorseddirs>${endorsed.dir}</endorseddirs>
                </compilerArguments>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.6</version>
            <executions>
                <execution>
                    <phase>validate</phase>
                    <goals>
                        <goal>copy</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${endorsed.dir}</outputDirectory>
                        <silent>true</silent>
                        <artifactItems>
                            <artifactItem>
                                <groupId>javax</groupId>
                                <artifactId>javaee-endorsed-api</artifactId>
                                <version>7.0</version>
                                <type>jar</type>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
WildFly Swarmの代わりに、別のJava EEベースのfat JARスタイルのフレームワーク、例えばPayara MicroやKumuluzEE、Apache TomEE embeddedなどを利用することもできます。
Payara Micro
http://www.payara.fish/payara_micro
KumuluzEE
https://ee.kumuluz.com/
TomEE Embedded
http://tomee.apache.org/advanced/tomee-embedded/index.html
では詳細に入っていきましょう。

Dynamic load balancing

Oracle Container Cloudを使用した水平方向へのスケーラビリティは非常に単純で、アプリケーションの追加インスタンスを生成するだけです。これは、アプリケーション・コンシューマ(ユーザーまたは他のアプリケーション)が個々のインスタンスの詳細を取り扱う必要がないよう、ロードバランサを用意していて、ロードバランサの座標(ホスト /ポート)だけを知っていればよい場合に有効です。問題は、ロードバランサが新しく生成されたアプリケーションインスタンス/コンテナを認識しないことです。Oracle Container Cloudは統合スタックを作成することができます。これにより、バックエンド(この例ではREST API)と(HAProxy)ロードバランサ・コンポーネントの両方を単一ユニットとして構成し、簡単に管理および編成できるだけでなく、動的なHAProxyの化身(Avatar)のためにレシピを提供することができます。

HAProxy on steroids

Oracle Container Cloud Githubリポジトリのアーティファクトを使い、confdおよびrunit用にカスタマイズされたDockerイメージの上に、特殊化された(Docker)HAProxyイメージを作成します。
HAProxy Load Balancer Image
https://github.com/oracle/docker-images/tree/0c7f9a90e4420e313f3aeba865cd064c2d138463/ContainerCloud/images/haproxy
confd - Manage local application configuration files using templates and data from etcd or consul
https://github.com/kelseyhightower/confd
runit - a UNIX init scheme with service supervision
http://smarden.org/runit/
confdは構成管理ツールであり、今回は実行中のアプリケーションインスタンスを動的に発見するために使用します。Oracle Container Cloudサービス内のネイティブ・サービス・ディスカバリに問い合せ、新しいアプリケーションインスタンスを検出する、新しいアプリケーション・インスタンスを検出するミニ・サービス・ディスカバリ・モジュールと考えてください。
Oracle® Cloud Using Oracle Container Cloud Service
Managing Entries in the Service Discovery Database to Enable Container Communication
http://docs.oracle.com/en/cloud/iaas/container-cloud/contu/managing-entries-service-discovery-database-enable-container-communication.html

Configuring our application to run on Oracle Container Cloud

Build Docker images

まず必要なDockerイメージを作成します。デモのため、Docker Hubのパブリックリポジトリ(abhirockzz)を使いますが、ご自身のパブリックリポジトリやプライベートリポジトリをお使いいただくことができます。
Docker engineが起動していることを確認してください。

Build the application Docker image

Dockerfileは以下のような感じです。
FROM anapsix/alpine-java:latest 
RUN mkdir app  
WORKDIR "/app"
COPY target/occ-haproxy-swarm.jar .
EXPOSE 8080
CMD ["java", "-jar", "occ-haproxy-swarm.jar"]
以下のコマンドを実行してイメージを作成します。
docker build –t <registry>/occ-wfly-haproxy:<tag> . e.g. docker build –t abhirockzz/occ-wfly-haproxy:latest .

Build Docker images for runit, confd, haproxy

依存するイメージを順にビルドしていきましょう。まずは


以下のコマンドを実行します。
cd ContainerCloud/images 
cd runit
make image
cd ../confd
make image
cd ../nginx-lb
make image

Check your local Docker repository

ここまででローカルのDockerリポジトリに必要な全てのイメージがそろいました。


Push Docker images

ではDockerイメージをレジストリにPushしましょう(今回の場合、筆者のパブリックDockerレジストリにPushします)。これにより、Oracle Container Cloudからアプリケーションスタックのデプロイ時にPullすることができます。Pushは以下のコマンドを実行します。
各セットアップ毎にレジストリやリポジトリの名前を調整する必要があります。
docker login 
docker push abhirockzz/occ-wfly-haproxy
docker push abhirockzz/haproxy
docker logout

Create the Stack

Stack作成のために、docker-composeに非常に似ているYAMLフォーマットの構成ファイルを利用します。この例では、サービス名(rest-api)をロードバランサ(HAProxy)サービスで参照しています。


これは、Oracle Container Cloudサービス・レジストリ内のキーに関する情報をHAProxyサービスに提供します。このレジストリを使って(前述の)confdサービスが実際に新しいアプリケーション・インスタンスを自動検出します。8080は公開されたポート番号ですが、これ自体がサービスレジストリのキーの一部でもあるため、ハードコードされています。

StacksメニューからNew Stackを選択してプロセスを開始します。


Advanced EditorをクリックしてYAMLコンテンツを入力します。



これで個々のサービスが見えるはずです。Stack Nameを指定して[Save]をクリックします。



Initiate Deployment


Stacksメニューに戻って、新規作成されたStackを[Deploy]をクリックしてデプロイします。


ロードバランシングをテストするため、rest-api(バックエンド)サービスの3個のインスタンスをデプロイし、1個の負荷分散(HAProxy)サービスと紐付けます。


数秒後、全てのコンテナが実行中状態になっていることを確認できるはずです。今回は、この3個のサービスと1個のha-proxyロードバランサのインスタンスが実行中になっています。


Service Discoveryメニューをチェックして書くインスタンスが存在することを確認しましょう。前述の通り、これはconfdサービスがアプリケーションの新規インスタンスを自動検出することでイントロスペクトされています(自動的にこのレジストリに追加されます)。

Test

HAProxyを経由してアプリケーションにアクセスすることができます。HAProxyコンテナが実行しているホストのパブリックIPを知っておく必要があります。(下図の通り)バックエンドのアプリケーションにアクセスするためにポート番号8886が既にマップ済みです。


以下のcURLコマンドを実行して確認しましょう。
for i in `seq 1 9`; do curl -w "\n" -X GET "http://<haproxy-container-public-IP>:8886/api/stocks?ticker=ORCL"; done 
9回呼び出し、(3個のインスタンス間で)負荷分散が動作していることを確認します。以下がその結果です。ハイライトされたテキストはレスポンスを返したインスタンスを指し示しています。3個のインスタンス間で負荷分散が均等になされています。


Scale up... and check again

スタックをスケールアップすることも簡単に繰り返し実施できます。デプロイメントに移動し、Change Scalingをクリックします。


少々したら、追加されたアプリケーション・インスタンス(5個目のインスタンス)が確認できることでしょう。コマンドを再度実行し、負荷分散が想定通り動作していることを確認しましょう。



[Cloud, JavaScript] Mocha.js for Test Automation of Node.js REST API on Oracle Developer Cloud Service

$
0
0
原文はこちら。
https://community.oracle.com/community/cloud_computing/platform-as-a-service-paas/oracle-developer-cloud-service/blog/2017/06/04/mochajs-for-test-automation-of-nodejs-rest-api-on-oracle-developer-cloud-service

このエントリでは、Oracle Developer Cloud Service上でMocha.jsという人気のあるテスティングフレームワークを使ったNode.jsベースのRESTサービスアプリケーションのテスト自動化を取り扱います。このNode.jsアプリケーションをOracle Application Container Cloud Serviceにデプロイします。

(注意)Developer Cloud Serviceを使ったNode.js RESTアプリケーションの開発、およびApplication Containerへのデプロイに関する詳細は、以下のエントリをご覧ください。
Oracle Developer Cloud to build and deploy Nodejs REST project on Application Container Cloud
https://community.oracle.com/community/cloud_computing/platform-as-a-service-paas/oracle-developer-cloud-service/blog/2016/09/07/oracle-developer-cloud-to-build-and-deploy-nodejs-rest-project-on-application-container-cloud

Tech Stack Used

Eclipse: Node.jsアプリケーション開発に使用するIDE
Express.js: REST Webサービス開発に使用するNode.jsモジュール
Grunt: デプロイ用にNode.jsコードアーカイブを生成するためのツール
Testing Framework: Mocha.js
Oracle Developer Cloud: Node.jsアプリケーションのCI、CDおよびその一環でのテスト自動化
Oracle Application Container Cloud: Node.jsベースのREST Webサービスデプロイ先のクラウドサービス

About Mocha framework:

Mochaは機能が豊富なJavaScriptテストフレームワークで、Node.jsならびにブラウザで動作します。Mochaテストフレームワークの主目的は非同期テストをシンプルにすることにあります。Mochaテストは所定の順番で動作します。これにより、柔軟で正確なレポートが作成しつつ、捕捉されない例外を正しいテストケースにマッピングできます。

Some of the salient features of Mocha framework:

  • ブラウザのサポート
  • シンプルな非同期サポート(promiseを含む)
  • テストカバレッジのレポート
  • テスト実行のためのJavaScript API
  • 捕捉されない例外を正しいテストケースにマッピング
  • 非同期テストタイムアウトのサポート
  • テスト再実行のサポート
  • テスト固有のタイムアウト
  • グローバル変数のリーク検知
  • 正規表現に一致するテストをオプションで実行
  • done()への複数呼び出しの検知
  • 利用したい任意のアサーションライブラリの利用

Setting up Mocha for Node.js application Testing:

以下のブログエントリに従ってNode.js RESTサービスアプリケーションを開発すると、Oracle Application Container Cloud Service上のNode.jsにデプロイされたRESTアプリケーションがあります。 このエントリではMochaTestという名前を付けました(もちろん自由に名前を付けることができます)。
Oracle Developer Cloud to build and deploy Nodejs REST project on Application Container Cloud
https://community.oracle.com/community/cloud_computing/platform-as-a-service-paas/oracle-developer-cloud-service/blog/2016/09/07/oracle-developer-cloud-to-build-and-deploy-nodejs-rest-project-on-application-container-cloud
サンプルを簡単にするため、Mocha.jsのテストスクリプトを 'MochaTest'フォルダに含めましたが、分離の観点から別のフォルダを選択することもできます。今回は、Mocha.jsベースのテスト自動化がDeveloper Cloud Serviceを使ってどのように動作するかを確認するためのサンプルアプリケーションゆえ、テストスクリプトを同じアプリケーションプロジェクトに保存することにしました。しかし、大規模なプロジェクトでは、包括的なテストスクリプトを使用して、テストスクリプトのために個別のGitリポジトリとプロジェクト(Developer Cloud Serviceの同じプロジェクトではあるものの、アプリケーション・プロジェクト・フォルダは異なります)を選択することができます。

下図はEclipseのMochaTestプロジェクトのスクリーンショットです。
2017-05-25 13_21_58-Java EE - Eclipse.png

Files for the Nodejs REST service:

  1. Gruntfile.js– ビルドタスクを定義
  2. manifest.json - main.jsという実行対象のmainファイルを定義(ACCSへのデプロイにおいて重要なファイル)
  3. main.js– 実際に実行されるサービスのコード
  4. package.json– 依存性を定義するファイル

File(s) for the test scripts:

test.js

このファイルにはNode.js REST Webサービスのテストスクリプトが含まれています。

Mocha.jsフレームワークの詳細を理解するには以下のリンクを参照してください。
Mocha - the fun, simple, flexible JavaScript test framework
https://mochajs.org/

A peek into the code snippets of the Nodejs application:

Gruntfile.js

アーカイブをOracle Application Container Cloud Serviceに正常にデプロイするため、manifest.jsonファイルを含めることが重要です。expressやbody-parserといったモジュールは、main.jsにおいてRESTサービスの実装に使用されるため、デプロイメントアーカイブ 'nodeappl.zip'に含める必要があります。
module.exports = function(grunt) {  

require('load-grunt-tasks')(grunt);

grunt.initConfig({
compress: {
main: {
options: {
archive: 'nodeappl.zip',
pretty: true
},
expand: true,
cwd: './',
src: ['./main.js','./manifest.json','./package.json','./node_modules/express/**/*','./node_modules/body-parser/**/*'],
dest: './'
}
}
});

grunt.registerTask('default', ['compress']);
};

manifest.json

属性 majorVersion はNode.jsのランタイムバージョンを定義します。これは今回は0.12で、属性 command はアーカイブデプロイメントで実行対象のmain.jsというメインサービスファイルを定義する必要があります。
{  
"runtime":{
"majorVersion":"0.12"
},
"command": "node main.js",
"release": {},
"notes": ""
}
(訳注)
Oracle Application Container Cloud Serviceで利用可能なランタイムバージョンは以下のURLを参照してください。
Oracle® Cloud Using Oracle Application Container Cloud Service
Creating an Application
http://docs.oracle.com/en/cloud/paas/app-container-cloud/csjse/creating-application.html#GUID-695C9491-2927-4E7A-AA14-754CEFE07D35__THISTABLEDESCRIBESADDITIONALFIELDSI-620AD53E

package.json

テストスクリプトを実行するためのコマンド 'mocha test.js'を実行する npm testが利用できるよう、Mochaテストフレームワーク・モジュールを開発依存性として含める必要があります。
{
"name": "MochaTest",
"version": "0.0.1",
"scripts": {
"start": "node main.js",
"test": "mocha test.js"
},
"dependencies": {
"body-parser": "^1.13.2",
"express": "^4.13.1",
"grunt": "^0.4.5",
"grunt-contrib-compress": "^1.3.0",
"grunt-hook": "^0.3.1",
"load-grunt-tasks": "^3.5.2",
"request": ""
},
"devDependencies": {
"mocha": "^3.3.0"
}
}

main.js

main.js ファイルにはget/post関数が含まれています。get関数は、静的なメッセージおよびfalseというエラー属性をレスポンスとして返します。post関数の 'add'は2個の数値をサービスの入力として受け取り、その和を返します。

Node.jsモジュールであるexpressおよびbodyParserはRESTサービス作成のために使っています。
ar express = require("express");  
var bodyParser = require("body-parser");
var app = express();
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
var router = express.Router();


router.get('/',function(req,res){
res.json({"error" : false, "message" : "Hello Abhinav!"});
});


router.post('/add',function(req,res){
res.json({"error" : false, "message" : "success", "data" : req.body.num1 + req.body.num2});
});


app.use('/',router);


app.listen(process.env.PORT || 3000,function(){
console.log("I am listening at PORT 3000");
})

A peek into the code snippet of the test script for the Nodejs application:

test.js

スクリプト中に3個のテストがあり、1個目はサービスが立ち上がっているかどうかを確かめるもの、2個目はadd関数が正しく動作しているかどうかを確かめるもの、最後の3個目はランダムなリソースをリクエストした場合に404を返すことを確かめるものです。

It uses the ‘request’ Node.jsモジュールを使ってテスト用アプリケーションURLを取得します。assert Node.jsモジュールも使っています。
var assert = require('assert');  
var request = require('request');
// UNIT test begin

describe("Unit Tests for the REST Service",function(){

// #1 should return home page
it("should find the service to be running",function(){
// calling home page api
request('https://mochatest-paasdemo015.apaas.us6.oraclecloud.com', function (error, response, body) {
assert.equal(response.statusCode, 200, 'rest url is up');
});
});

it("should add two number",function(){
request({
url: 'https://mochatest-paasdemo015.apaas.us6.oraclecloud.com/add',
method: 'POST',
json: {num1: 10, num2: 20}
}, function(error, response, body){
assert.equal(body.data, 30, 'correct total');
});
});

it("should return 404",function(){
request('https://mochatest-paasdemo015.apaas.us6.oraclecloud.com/random',
function (error, response, body) {
assert.equal(response.statusCode, 404, '404 error for random url');
});
})
});

Build Configuration:

テストケースを実行するため、個別のビルドジョブをDeveloper Cloud Serviceで構成します。下図はビルドジョブの呼び出しの流れを示したものです。


下図は、Node.jsアプリケーションをビルド、デプロイするNodeApplBuildJobビルドジョブの構成画面のスクリーンショットです。ビルドジョブの名前は自由に設定できます。今回は‘NodeApplBuildJob’としています。これはNode.jsアプリケーションなので、JDKはデフォルトのままにしておきます。

Node.jsアプリケーションコードをアップロードしたリポジトリを選択します。前述の通り、Node.jsアプリケーション関連コードを含む同じプロジェクトに、このテストスクリプトが含まれています。


SCMポーリングをトリガーとして設定します。これにより、コードをGitリポジトリにアップロードするたびに、上のビルドトリガー図に示したように、'NodeApplBuildJob'が呼び出されます。
2017-05-26 17_18_10-Build_ BlogProject - Oracle Developer Cloud Service.png
今回は、実行シェル構築ステップを使います。ビルドステップの一環として、まずフォルダをプロジェクトフォルダ 'MochaTest'に変更します。以下のスクリーンショットのように、npm installを使用して、必要なNode.jsモジュールをすべてインストールします。続いて、grunt コマンドを使用して、デプロイ用のzipアーカイブを作成します。
2017-05-26 17_18_36-Build_ BlogProject - Oracle Developer Cloud Service.png
post buildのタブで、gruntビルドスクリプト実行の結果生成されたzipアーカイブを構成します。また、Application Container Cloud ServiceのNodeコンテナ上へのアーカイブのデプロイも構成します。
2017-05-26 17_19_07-Build_ BlogProject - Oracle Developer Cloud Service.png

下図では、Developer Cloud Serviceでビルド済みのアーカイブをApplication Container Cloud Serviceにデプロイするためにデプロイメントを構成しています。
2017-05-26 18_31_44-Deploy _ BlogProject.png
2017-05-26 18_31_11-Deploy _ BlogProject.png


以下は、Mochaテストスクリプトを実行するNodeTestBuildJobのビルドジョブ設定スクリーンショットです。
NodeApplBuildジョブの場合と同様に、ビルドジョブに名前を付けることができます。今回はNodeTestBuildJobという名前を付けました。これはNode.jsアプリケーションのため、JDKはデフォルトのままにしておくことができます。
2017-05-26 18_37_57-Build_ BlogProject - Oracle Developer Cloud Service.png
Node.jsアプリケーションは、test.jsがアプリケーションコードと同じリポジトリにあるため、同じリポジトリを使います。
2017-05-26 18_38_12-Build_ BlogProject - Oracle Developer Cloud Service.png

アプリケーションのビルドジョブであるNodeApplBuildJobの実行完了後、テストビルドジョブが呼び出されます。
2017-05-26 18_38_25-Build_ BlogProject - Oracle Developer Cloud Service.png

ここでも実行シェルビルドステップを使用します。test.jsがMochTestプロジェクトフォルダにあるので、フォルダを MochaTest に変更します。Node.jsモジュールのMochaを開発依存性としてインストールし、npm testを使用してpackage.jsonのscriptsの箇所に記載した 'mocha test.js'コマンドを実行を開始します。
2017-05-26 18_38_40-Build_ BlogProject - Oracle Developer Cloud Service.png

テストスクリプトをビルドジョブ実行時に実行します。以下がテスト結果で、ビルドジョブコンソールで見ることができます。
2017-05-26 18_39_02-Build_ BlogProject - Oracle Developer Cloud Service.png

[Java, Cloud] Develop Microservices application using CQRS and Event sourcing patterns in Oracle Cloud

$
0
0
原文はこちら。
https://community.oracle.com/community/cloud_computing/oracle-cloud-developer-solutions/blog/2017/03/30/develop-microservices-application-using-cqrs-and-event-sourcing-patterns

このエントリでは、CQRSとイベントソーシングパターンを使用して、イベント駆動のマイクロサービスアプリケーションを構築する方法を紹介します。 以下は、このエントリで説明する概念を簡潔にまとめたものです。詳細は、このブログの最後にあるリソースから入手してください。

What is a Microservice?

このアーキテクチャースタイルにはずばりこれ、という定義はありませんが、Adrian Cockcroftによれば、マイクロサービスアーキテクチャは、有界コンテキストを持つ要素を疎結合で構成したサービス指向アーキテクチャと定義しています。
Adrian Cockcroftについて
http://www.battery.com/our-team/member/adrian-cockcroft/

What is a Bounded Context?

Bounded Context(有界コンテキスト)とは、ドメインモデルやデータモデル、アプリケーションサービスといったシングルドメインの詳細をカプセル化するというコンセプトで、別の有界コンテキストやドメインとの統合ポイントを定義します。

What is CQRS?

Command Query Responsibility Segregation (CQRS) とは、ドメイン操作をクエリとコマンドの2つのカテゴリに分けるアーキテクチャパターンです。クエリは状態を変更せずに結果を返すだけですが、コマンドはドメインモデルの状態を変更する操作です。

Why CQRS?

アプリケーション・ライフサイクルでは、論理モデルがより複雑で構造化されると、ユーザーエクスペリエンスに影響を与える可能性があるため、ユーザーエクスペリエンスは、コアシステムとは独立していなければなりません。
スケーラブルでアプリケーションのメンテナンスを簡単にするため、読み取りモデルと書き込みモデル間の制約を減らす必要があります。読み書きを分ける理由は以下の通りです。
  • スケーラビリティ
    読み取りが書き込みを上回るので、それぞれのスケール要件が異なり、より適切に対応できる
  • フレキシビリティ
    別々の読み取り/書き込みモデル
  • 複雑性の軽減
    複雑さを別々の問題にシフト

What is Event sourcing?

イベントソーシングは、異なるイベント中心のアプローチを使ってビジネスエンティティを永続化することで、アトミック性を実現します。
WhyEventSourcing
https://github.com/cer/event-sourcing-examples/wiki/WhyEventSourcing
エンティティの現在の状態を格納するのではなく、アプリケーションは、エンティティの状態を変更した一連の「イベント」を格納します。アプリケーションは、イベントを再生してエンティティの現在の状態を再構築できます。イベントの保存は単一の操作であるため、本質的にアトミックであり、分散トランザクションに通常関連付けられる2PC(2フェーズコミット)を必要としません。

Overview

このエントリでは、CQRSとイベントソーシングパターンを適用して、追加、削除、および読み取り操作を伴う「カート」という単一の有界コンテキストで構成される単純なマイクロサービスアプリケーションを開発する方法について説明します。このサンプルには機能的な意味はありませんが、基礎となるパターンとその実装を理解するのに十分でしょう。次の図は、CQRSおよびイベントソーシングパターンを使用してアプリケーションを構築する際のアクティビティの概念フローを示しています。

cqrs-es_1.jpg
Figure 1 CQRS and Event sourcing
このエントリで紹介しているサンプルで利用しているテクノロジースタックは以下の通りです。
  • Spring Boot : https://projects.spring.io/spring-boot/
    アプリケーションの構築およびパッケージング
  • Axon : http://www.axonframework.org/
    CQRSとイベントソーシングのためのSpringを使ったフレームワーク。 AxonはJava用のオープンソースのCQRSフレームワークで、CQRSとイベントソーシング・アーキテクチャパターンを使用してアプリケーションを構築するのに役立つ、集約、リポジトリー、イベントバスといった最も重要なビルディングブロックの実装を提供します。また、上記のビルディングブロックの独自の実装を提供することもできます。
  • Oracle Application Container Cloud : https://cloud.oracle.com/ja_JP/acc
    アプリケーションのデプロイ先
このような前提を踏まえて、サンプルの構築をすすめていきましょう。

Identify Aggregate Root

第1のステップは、有界コンテキストを識別し、有界コンテキストのドメインエンティティを識別することです。これは('account'、 'order' ...といった)Aggregate Root(集約ルート)を定義するのに役立ちます。Aggregate(集約)とは、常に一貫性のある状態に保たれるエンティティまたはエンティティのグループです。Aggregate Rootは、この一貫性のある状態を維持する責任を負う集約ツリーの最上位にあるオブジェクトです。
今回は簡単のため、ドメインモデルの唯一のAggregate Rootとして「カート」を考えます。 通常のショッピングカートのように、カート内のアイテムは、そのカートへの追加または削除されたものによって調整されます。

Define Commands

このAggregate Rootには2個のコマンドがあります。
  • Cartへの追加Command
    AddToCartCommand クラスでモデリング
  • Cartからの削除Command
    RemoveFromCartCommand クラスでモデリング
public class AddToCartCommand { 

    private final String cartId;
    private final int item;

    public AddToCartCommand(String cartId, int item) {
        this.cartId = cartId;
        this.item = item;
    }

    public String getCartId() {
        return cartId;
    }

    public int getItem() {
        return item;
    }
}

public class RemoveFromCartCommand {

    private final String cartId;
    private final int item;

    public RemoveFromCartCommand(String cartId, int item) {
        this.cartId = cartId;
        this.item = item;
    }

    public String getCartId() {
        return cartId;
    }

    public int getItem() {
        return item;
    }
}
ご存じのとおり、これらのコマンドはただのPOJOで、システム内で何が起こる必要があるのか、また必要な情報とともにシステム内で発生する必要のあるものごとを捕捉するために使います。Axonフレームワークでは、インターフェイスの実装やクラスの拡張を行うコマンドは必要ありません。

Define Command Handlers

コマンドにはハンドラが1つだけあります。以下のクラスはカートへの追加およびカートからの削除コマンドのハンドラを表します。
@Component  
public class AddToCartCommandHandler {

private Repository repository;

@Autowired
public AddToCartCommandHandler(Repository repository) {
this.repository = repository;
}

@CommandHandler
public void handle(AddToCartCommand addToCartCommand){
Cart cartToBeAdded = (Cart) repository.load(addToCartCommand.getCartId());
cartToBeAdded.addCart(addToCartCommand.getItem());
}
}

@Component
public class RemoveFromCartHandler {

private Repository repository;

@Autowired
public RemoveFromCartHandler(Repository repository) {
this.repository = repository;
}

@CommandHandler
public void handle(RemoveFromCartCommand removeFromCartCommand){
Cart cartToBeRemoved = (Cart) repository.load(removeFromCartCommand.getCartId());
cartToBeRemoved.removeCart(removeFromCartCommand.getItem());
}
}
Spring BootともにAxonを使用しているため、上で定義したSpring Beanには@CommandHandlerというアノテーションが付いたメソッドがあり、これをコマンドハンドラとして扱うことができます。@Componentアノテーションは、アプリケーション起動時にこれらのBeanをスキャンし、任意のAuto wired ResourceをこのBeanに注入します。Aggregateに直接アクセスするのではなく、AxonフレームワークのドメインオブジェクトであるRepositoryが、Aggregateの取得と永続化を抽象化します。

Application Startup

以下のAppConfigurationクラスは、アプリケーション・デプロイ時に初期化され、パターン実装時に必要なコンポーネントを作成するSpring構成クラスです。
@Configuration 
@AnnotationDriven
public class AppConfiguration {
 
    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder
                .create()
                .username("sa")
                .password("")
                .url("jdbc:h2:mem:axonappdb")
                .driverClassName("org.h2.Driver")
                .build();
    }

    /**
    * Event store to store events
    */
    @Bean
    public EventStore jdbcEventStore() {
        return new JdbcEventStore(dataSource());
    }

    @Bean
    public SimpleCommandBus commandBus() {
        SimpleCommandBus simpleCommandBus = new SimpleCommandBus();
        return simpleCommandBus;
    }

    /**
    *  Cluster event handlers that listens to events thrown in the application.
    */
    @Bean
    public Cluster normalCluster() {
        SimpleCluster simpleCluster = new SimpleCluster("simpleCluster");
        return simpleCluster;
    }


    /**
    * This configuration registers event handlers with defined clusters
    */
    @Bean
    public ClusterSelector clusterSelector() {
        Map<String, Cluster> clusterMap = new HashMap<>();
        clusterMap.put("msacqrses.eventhandler", normalCluster());
        return new ClassNamePrefixClusterSelector(clusterMap);
    }

    /**
    *The clustering event bus is needed to route events to event handlers in the clusters.
    */
    @Bean
    public EventBus clusteringEventBus() {
        ClusteringEventBus clusteringEventBus = new ClusteringEventBus(clusterSelector(), terminal());

        return clusteringEventBus;
    }

    /**
    * Event Bus Terminal publishes domain events to the cluster
    *
    */
    @Bean
    public EventBusTerminal terminal() {
        return new EventBusTerminal() {
            @Override
            public void publish(EventMessage... events) {
                normalCluster().publish(events);
            }
            @Override
            public void onClusterCreated(Cluster cluster) {
            }
        };
    }

    /**
    * Command gateway through which all commands in the application are submitted
    *
    */

    @Bean
    public DefaultCommandGateway commandGateway() {
        return new DefaultCommandGateway(commandBus());
    }

    /**
    * Event Repository that handles retrieving of entity from the stream of events.
    */
    @Bean
    public Repository<Cart> eventSourcingRepository() {
        EventSourcingRepository eventSourcingRepository = new EventSourcingRepository(Cart.class, jdbcEventStore());
        eventSourcingRepository.setEventBus(clusteringEventBus());

        return eventSourcingRepository;
    }
Axonが提供する、このクラスで初期化された主要なインフラストラクチャコンポーネントを見てみましょう。

Command bus

図1の通り、command bus(コマンドバス)は、それぞれのコマンドハンドラにコマンドをルーティングするコンポーネントです。Axon Frameworkには、コマンドをコマンド・ハンドラに渡すために使用可能な種々のCommand Busが付属しています。 AxonのCommand Busの実装の詳細は以下のURLを参照してください。
Axon Framework 2.0.9 Reference Guide
Command Handling
http://www.axonframework.org/docs/2.0/command-handling.html
この例では、SpringのアプリケーションコンテキストでBeanとして構成されているSimpleCommandBusを使用します。

Command Gateway

Command Bus直接コマンドを送信できますが、通常はCommand Gatewayを使用することをお勧めします。Command Gatewayを使用することで、開発者はコマンドのインターセプト、障害時の再試行の設定といった機能を実行できます。この例では、Command Busを直接使用せず、コマンドを送信するSpring Beanとして構成されているDefaultCommandGatewayを使用します。これはAxonがデフォルトで提供しているものです。

Event Bus

図1の通り、Aggregate Rootで開始されたコマンドは、イベントとして送信され、Event Storeで永続化されます。Event Busは、イベントをイベントハンドラにルーティングする基盤です。Event Busはメッセージディスパッチの観点からCommand Busに似ていますが、基本的に異なるものです。

Command Busは、近い将来に何が起こるかを定義するコマンドとともに動作し、コマンドを解釈するコマンドハンドラは1つだけです。それに対し、Event Busでは、イベントをルーティングし、イベントに対してゼロ個以上のハンドラを使って、過去に発生したアクションを定義します。

Axonは、Event Busの複数の実装を定義していますが、今回はSpring Beanとして再度ワイヤリングされたClusteringEventBusを使用します。AxonのEvent Bus実装の詳細については、以下のURLを参照してください。
Axon Framework 2.0.9 Reference Guide
6. Event Processing
http://www.axonframework.org/docs/2.0/event-processing.html

Event Store

リポジトリはドメインオブジェクトの現在の状態ではなくドメインイベントを格納するため、イベントストアを構成する必要があります。Axon Frameworkでは、JDBC、JPA、ファイルシステムなどの複数の永続化方式を使用してイベントを格納できます。今回は、JDBCイベントストアを使用します。

Event Sourcing Repository

今回はAggregate Rootを永続メカニズムの表現から作成せず、Event sourcingリポジトリを使って構成できるイベントストリームから作成します。ドメインイベントを発行する予定であるため、前に定義したEvent Busを使用してリポジトリを設定します。

Database

今回はデータストアとしてインメモリデータベース(h2)を使います。Spring Bootのapplication.propertiesにはデータソース構成の設定が含まれています。
# Datasource configuration 
spring.datasource.url=jdbc:h2:mem:axonappdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.validation-query=SELECT 1;
spring.datasource.initial-size=2
spring.datasource.sql-script-encoding=UTF-8

spring.jpa.database=h2
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
前述の通り、この例ではJDBCイベントストアを使ってシステムで生成されるイベントを格納します。これらのイベントをAxon Frameworkが指定する(Axon Frameworkイベントインフラストラクチャの)デフォルト表に格納します。以下のスタートアップクラスを使って、この例で必要なデータベース表を作成します。
@Component  
public class Datastore {

@Autowired
@Qualifier("transactionManager")
protected PlatformTransactionManager txManager;

@Autowired
private Repository repository;

@Autowired
private javax.sql.DataSource dataSource;
// create two cart entries in the repository used for command processing
@PostConstruct
private void init() {

TransactionTemplate transactionTmp = new TransactionTemplate(txManager);
transactionTmp.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
UnitOfWork uow = DefaultUnitOfWork.startAndGet();
repository.add(new Cart("cart1"));
repository.add(new Cart("cart2"));
uow.commit();
}
});

// create a database table for querying and add two cart entries
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute("create table cartview (cartid VARCHAR , items NUMBER )");
jdbcTemplate.update("insert into cartview (cartid, items) values (?, ?)", new Object[]{"cart1", 0});
jdbcTemplate.update("insert into cartview (cartid, items) values (?, ?)", new Object[]{"cart2", 0});
}
...
}
このスタートアップクラスは、コマンド処理に使う2個のカートエントリをリポジトリに作成し、クエリ処理に使うデータベース表(cartview)を作成します。

ここまでで実施したことをまとめておきます。
  • Aggregate RootとしてCartを識別し、Cartへのアイテム追加および削除のコマンドおよびコマンドハンドラを定義した
  • CQRS およびイベントソーシングに必要な基盤コンポーネントを初期化するスタートアップクラスを定義した
  • データベース表の作成ならびにこのサンプルが必要とするデータ設定のためのスタートアップクラスも定義した
以下で定義するAggregateRootの"Cart"を見ていきましょう。

Aggregate Root

public class Cart extends AbstractAnnotatedAggregateRoot { 
    @AggregateIdentifier
    private String cartid;

    private int items;

    public Cart() {
    }

    public Cart(String cartId) {
        apply(new CartCreatedEvent(cartId));
    }

    @EventSourcingHandler
    public void applyCartCreation(CartCreatedEvent event) {
        this.cartid = event.getCartId();
        this.items = 0;
    }

    public void removeCart(int removeitem) {

        /**
        * State is not directly changed, we instead apply event that specifies what happened. Events applied are stored.
        */
        if(this.items > removeitem && removeitem > 0)
            apply(new RemoveFromCartEvent(this.cartid, removeitem, this.items));
    }

    @EventSourcingHandler
    private void applyCartRemove(RemoveFromCartEvent event) {
    /**
    * When events stored in the event store are applied on an Entity this method is
    * called. Once all the events in the event store are applied, it will bring the Cart * to the most recent state.
    */

        this.items -= event.getItemsRemoved();
    }

    public void addCart(int item) {
        /**
        * State is not directly changed, we instead apply event that specifies what happened. Events applied are stored.
        */
        if(item > 0)    
            apply(new AddToCartEvent(this.cartid, item, this.items));
    }

    @EventSourcingHandler
    private void applyCartAdd(AddToCartEvent event) {
    /**
    * When events stored in the event store are applied on an Entity this method is
    * called. Once all the events in the event store are applied, it will bring the
    * Cart to the most recent state.
    */

        this.items += event.getItemAdded();
    }

    public int getItems() {
        return items;
    }

    public void setIdentifier(String id) {
        this.cartid = id;
    }

    @Override
    public Object getIdentifier() {
        return cartid;
    }
}
以下はAggregate Rootの定義のキーポイントです。
  1. @AggregateIdentifier は、エンティティのIDを示すフィールドをマークする、JPAにおける @Id と似ている
  2. ドメイン駆動デザインでは、ドメインエンティティに関連するビジネスロジックを含めることを推奨しており、そのロジックが上記定義にあるビジネスメソッドである。詳細はReferencesのセクションを参照のこと。
  3. コマンドが呼び出されると、ドメインオブジェクトをリポジトリから取得し、それぞれのメソッド(例えばaddCart)がそのドメインオブジェクト(ここではCart)で呼び出される。
    1. ドメインオブジェクトは直接状態を変更せずに、適切なイベントを適用する
    2. イベントはイベントストアに保存され、そのイベントに対応するハンドラが呼び出され、ドメインオブジェクトの変更が発生する。
  4. CartというAggregate Rootは更新(つまりコマンドによる状態変更)にのみ利用されることに注意する必要がある。全てのクエリリクエストは、(次セクションで説明する)別のデータベースエンティティで処理される。
ではイベントならびにCartエンティティから呼び出されるドメインイベントを管理するイベントハンドラを見ていきましょう。

Events

前のセクションで説明したように、Cartエンティティで呼び出される2つのコマンド、Cartへの追加とCartからの削除があります。これらのコマンドがAggregate Rootで実行されると、以下に示すAddToCartEventとRemoveFromCartEventという2つのイベントを生成します。
public class AddToCartEvent {  

private final String cartId;
private final int itemAdded;
private final int items;
private final long timeStamp;

public AddToCartEvent(String cartId, int itemAdded, int items) {
this.cartId = cartId;
this.itemAdded = itemAdded;
this.items = items;
ZoneId zoneId = ZoneId.systemDefault();
this.timeStamp = LocalDateTime.now().atZone(zoneId).toEpochSecond();
}

public String getCartId() {
return cartId;
}

public int getItemAdded() {
return itemAdded;
}

public int getItems() {
return items;
}

public long getTimeStamp() {
return timeStamp;
}
}

public class RemoveFromCartEvent {
private final String cartId;
private final int itemsRemoved;
private final int items;
private final long timeStamp;

public RemoveFromCartEvent(String cartId, int itemsRemoved, int items) {
this.cartId = cartId;
this.itemsRemoved = itemsRemoved;
this.items = items;
ZoneId zoneId = ZoneId.systemDefault();
this.timeStamp = LocalDateTime.now().atZone(zoneId).toEpochSecond();
}

public String getCartId() {
return cartId;
}

public int getItemsRemoved() {
return itemsRemoved;
}

public int getItems() {
return items;
}

public long getTimeStamp() {
return timeStamp;
}
}

Event Handlers

上述のイベントは以下のイベントハンドラで処理されます。
@Component  
public class AddToCartEventHandler {

@Autowired
DataSource dataSource;

@EventHandler
public void handleAddToCartEvent(AddToCartEvent event, Message msg) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

// Get current state from event
String cartId = event.getCartId();
int items = event.getItems();
int itemToBeAdded = event.getItemAdded();
int newItems = items + itemToBeAdded;


// Update cartview
String updateQuery = "UPDATE cartview SET items = ? WHERE cartid = ?";
jdbcTemplate.update(updateQuery, new Object[]{newItems, cartId});
}
}

@Component
public class RemoveFromCartEventHandler {

@Autowired
DataSource dataSource;

@EventHandler
public void handleRemoveFromCartEvent(RemoveFromCartEvent event) {

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

// Get current state from event
String cartId = event.getCartId();
int items = event.getItems();
int itemsToBeRemoved = event.getItemsRemoved();
int newItems = items - itemsToBeRemoved;

// Update cartview
String update = "UPDATE cartview SET items = ? WHERE cartid = ?";
jdbcTemplate.update(update, new Object[]{newItems, cartId});

}
}
お気づきの通り、イベントハンドラはcartviewというデータベース表を更新します。この表はCartエンティティをクエリする際に使われます。コマンドをあるドメインで実行している間、イベントソーシングでCQRSを実現することにより、クエリリクエストは別のドメインで処理されます。

Controllers

この例では、2個のSpringコントローラクラスを定義しています。一つはCartドメインの更新、一つはCartドメインのクエリのためのクラスです。以下のようにブラウザからRESTエンドポイントを呼び出すことができます。

  • http://<host>:<port>/add/cart/<noOfItems>
  • http://<host>:<port>/remove/cart/<noOfItems>
  • http://<host>:<port>/view

@RestController  
public class CommandController {

@Autowired
private CommandGateway commandGateway;

@RequestMapping("/remove/{cartId}/{item}")
@Transactional
public ResponseEntity doRemove(@PathVariable String cartId, @PathVariable int item) {
RemoveFromCartCommand removeCartCommand = new RemoveFromCartCommand(cartId, item);
commandGateway.send(removeCartCommand);

return new ResponseEntity<>("Remove event generated. Status: "+ HttpStatus.OK, HttpStatus.OK);
}

@RequestMapping("/add/{cartId}/{item}")
@Transactional
public ResponseEntity doAdd(@PathVariable String cartId, @PathVariable int item) {

AddToCartCommand addCartCommand = new AddToCartCommand(cartId, item);
commandGateway.send(addCartCommand);

return new ResponseEntity<>("Add event generated. Status: "+ HttpStatus.OK, HttpStatus.OK);
}
}

@RestController
public class ViewController {

@Autowired
private DataSource dataSource;

@RequestMapping(value = "/view", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity getItems() {

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
List<Map<String, Integer>> queryResult = jdbcTemplate.query("SELECT * from cartview ORDER BY cartid", (rs, rowNum) -> {
return new HashMap<String, Integer>() {{
put(rs.getString("CARTID"), rs.getInt("ITEMS"));
}};
});

if (queryResult.size() > 0) {
return new ResponseEntity<>(queryResult, HttpStatus.OK);
}
else {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
}
}

Deployment

Spring Bootを使ってアプリケーションを実行可能なJarファイルとしてパッケージングし、アプリケーションをOracle Application Container Cloud Serviceにデプロイします。以下のSpring Bootクラスでアプリケーションを初期化します。
@SpringBootApplication  
public class AxonApp {

// Get PORT and HOST from Environment or set default
public static final Optional<String> host;
public static final Optional<String> port;
public static final Properties myProps = new Properties();

static {
host = Optional.ofNullable(System.getenv("HOSTNAME"));
port = Optional.ofNullable(System.getenv("PORT"));
}

public static void main(String[] args) {
// Set properties
myProps.setProperty("server.address", host.orElse("localhost"));
myProps.setProperty("server.port", port.orElse("8128"));

SpringApplication app = new SpringApplication(AxonApp.class);
app.setDefaultProperties(myProps);
app.run(args);
}
}
以下のコンテンツを持つXMLファイルを作り、pom.xmlと同じディレクトリに配置します。このファイルは、Oracle Application Container Cloud Serviceへデプロイされるデプロイメント・アセンブリを指定するものです。
<assembly 
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>dist</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<files>
<file>
<source>manifest.json</source>
<outputDirectory></outputDirectory>
</file>
</files>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>
To let Application Container cloud know the jar to run once the application is deployed, you need to create a “manifest.json” file specifying the jar name as shown below:
{
"runtime": {
"majorVersion": "8"
},
"command": "java -jar AxonApp-0.0.1-SNAPSHOT.jar",
"release": {},
"notes": "Axon Spring Boot App"
}

下図はこのサンプルのプロジェクト構造を示しています。
Figure 2 Project Structure
アプリケーションJarファイルは上記のmanifestファイルとともにZipにまとめられ、Application Container Cloud Serviceにデプロイするためにアップロードされます。Spring BootアプリケーションのApplication Container Cloud Serviceへのデプロイについて詳細は以下のURLをご覧ください。
Deploying an Application to Oracle Application Container Cloud Service
http://www.oracle.com/webfolder/technetwork/tutorials/obe/cloud/apaas/deployment/deployment.html
アプリケーションが無事にデプロイ完了したら、以下のURLを使ってCartのサービスを呼び出すことができます。
  • http://<host>:<port>/view
  • http://<host>:<port>/add/cart/<noOfItems>
  • http://<host>:<port>/remove/cart/<noOfItems>
まず RESTエンドポイント "view"を呼び出すと、スタートアップクラスに追加した2つのカートと、追加されたアイテムの数が表示されます。他の2つのRESTサービスを呼び出してCartからアイテムを追加や削除、view RESTサービスを使用して更新された項目数を取得できます。REST呼び出しの結果は、その時点でのCart内のアイテム個数ならびにCartを示すシンプルなJSON構造として取得できます。

Conclusion

このエントリでは、CQRSとイベントソーシングパターンを使用したマイクロサービスアプリケーションの開発について紹介しました。この分野における他の先進的な概念や最新のアップデートについては、以下のリソースを参照してください。

References

[Linux, Cloud] Oracle Ksplice on Oracle Linux in Bare Metal Cloud

$
0
0
原文はこちら。
https://blogs.oracle.com/wim/oracle-ksplice-on-oracle-linux-in-bare-metal-cloud

Oracle Cloudを使用することの大きな利点の1つは、完全なOracle Linuxサポートが含まれていることです。Oracle Cloudを使用すると、Oracle Linux Premier Supportで得られるサービスはすべて含まれており、追加費用は必要ありません。

Oracle Kspliceはそのようなサービスです。
Oracle Ksplice
http://www.ksplice.com/
Oracle Cloud以外でOracle Kspliceを使用する場合、インストール時にOracle LinuxサーバーをUnbreakable Linux Network (ULN)に登録し、生成されたアクセス・キーを使用してKsplice Uptrackを構成します。
Unbreakable Linux Network (ULN)
http://linux.oracle.com
ですが、Oracle Cloud(Oracle Public CloudとOracle Bare Metal Cloud Services、以下BMCS)でお使いの場合、非常に簡単です。
Oracle Cloud
https://cloud.oracle.com/ja_JP/home
Oracle Cloud上のインスタンスはすべて、kspliceサーバに即座にアクセスできます。

BMCSに既存のOracle Linuxインスタンスを持つお客様またはご利用の方の場合、Kspliceを有効にするための簡単な手順をいくつか実行する必要があります。現在デフォルトでイメージにuptrackツールを追加している作業をしているため、もうすぐすると、この構成作業をする必要はなくなります。

今すぐKspliceを有効にするには:

opcユーザー(またはroot)としてOracle Linuxインスタンスにログインします。
# sudo bash
uptrackクライアントをダウンロードします。
# wget -N https://www.ksplice.com/uptrack/install-uptrack
cURLがお好みであれば、こちらで。
# curl -O https://www.ksplice.com/uptrack/install-uptrack
クライアントをインストールし、このキーを使っていることを確認しましょう。このキーはBMCSでのみ有効で、一般的な識別子です。
# sh install-uptrack dfc21b3ced9af52f6a8760c1b1860f928ba240970a3612bb354c84bb0ce5903e --autoinstall
このコマンドを使って、ダウンロード済みのスクリプトを展開し、unpackユーティリティ(Kspliceクライアントツール)をインストールします。接続エラーを無視するには以下の手順が必要です。

もう一つ、上記のキーが機能するためには、uptrackツールの接続先を特定のアップデートサーバーに指定する必要があります。
/etc/uptrack/uptrack.confを編集します。
# The location of the Uptrack updates repository.

update_repo_url=https://oraclecloud-updates-ksplice.oracle.com/update-repository
これで終わりです。
# uptrack-upgrade
Nothing to be done.
Your kernel is fully up to date.
Effective kernel version is 4.1.12-94.3.6.el6uek
BYOLのインスタンスの場合、上記の手順も自動化しますが、少なくともこれですぐに利用できるようになります。

[Database] Python cx_Oracle 6.0 RC 1 is now on PyPI

$
0
0
原文はこちら。
https://blogs.oracle.com/opal/python-cx_oracle-60-rc-1-is-now-on-pypi

Python cx_Oracle 6.0のRC1(Release Candidate 1)がPyPIからご利用いただけるようになりました。是非お試しいただいて、フィードバックください。
python-cx_Oracle Issueページ
https://github.com/oracle/python-cx_Oracle/issues
Python cx_Oracle はOracle DatabaseのPython Interfaceです。Version 6は新しいODPI-C抽象化層をベースにしており、これもまた現在Release Candidateフェーズです。
ODPI-C (Oracle Database Programming Interface for Drivers and Applications)
https://github.com/oracle/odpi
この層のおかげで、cx_Oracleコード自体を大幅にシンプルにすることができました。

final beta以後、cx_Oracle RC1に少し微調整が入っていますので、リリースノートをご覧ください。
cx_Oracle Release Notes
Version 6.0 rc 1 (June 2017)
http://cx-oracle.readthedocs.io/en/latest/releasenotes.html#version-6-0-rc-1-june-2017
変更点のいくつかをご紹介します。

  • ODPI-CがLONGおよびLONG RAW列のバッファサイズを自動的に管理するため、Cursor.setoutputsize() メソッドは不要になりました。
  • セッションプールを作成したり、Python 2.7でパスワードを変更したりするために、(文字列に加えて)unicodeを使用することができます。

ODPI-Cを使うことで、Python Wheelを作成でき、インストールがより簡単になりました。
PyPIからcx_Oracle 6.0 RC 1をインストールするには、以下のコマンドを使ってください。
python -m pip install cx_Oracle --pre
cx_Oracle 6.0rc1 - Python interface to Oracle
https://pypi.python.org/pypi/cx_Oracle/6.0rc1
あと、実行時にOracle Client 12cR2、12cR1、11gR2のライブラリ(Oracle Instant Client Basicパッケージ)にPATHを通しておく必要があります。
Oracle Instant Client
http://www.oracle.com/technetwork/database/features/instant-client/
cx_Oracleのドキュメントは以下のURLからどうぞ。
cx_Oracle documentation
http://cx-oracle.readthedocs.io/en/latest/

[JavaScript, Database] Node-oracledb 2.0.13-Development is now on GitHub

$
0
0
原文はこちら。
https://blogs.oracle.com/opal/node-oracledb-2013-development-is-now-on-github

Node-oracledb 2.0.13-DevelopmentがGitHubから利用いただけるようになりました。Node-oracledbはNode.jsでOracle Databaseを使うためのインターフェースです。

Top features:

  • Version 2はODPI-C抽象化レイヤーをベースにしています。
    ODPI Oracle Database Programming Interface for Drivers and Applications
    https://github.com/oracle/odpi
  • サポートされるデータ型が増えました。
完全な変更履歴(Changelog)は以下をご覧ください。
Change Log
https://github.com/oracle/node-oracledb/blob/dev-2.0/CHANGELOG.md
node-oracledb 2.0.13-Developmentのドキュメントは以下からどうぞ。
node-oracledb 2.0 Documentation for the Oracle Database Node.js Add-on
https://github.com/oracle/node-oracledb/blob/dev-2.0/doc/api.md
是非テストいただき、2.0 Development リリースサイクルの間に、出来るだけ早期に問題をレポートいただきたく思います。
node-oracledb Issue tracker
https://github.com/oracle/node-oracledb/issues
これはDevelopment Releaseなので、まだ粗い部分があることは承知しています。GitHubのIssueを使ってトラッキングを開始します。
Tracking node-oracledb 2.0.13-Development issues
https://github.com/oracle/node-oracledb/issues/716
完全なインストール手順は以下からご覧いただけます。
Installing node-oracledb Version 2
https://github.com/oracle/node-oracledb/blob/dev-2.0/INSTALL.md
しかし、node-oracledb 2.0はまだnpmに上がっていませんので、GitHubから以下のようにインストールする必要があります。
oracledb on npm
https://www.npmjs.com/package/oracledb
npm install oracle/node-oracledb.git#dev-2.0
Oracle Client 12.2、12.1、11.2のいずれかのライブラリ(例えばOracle Instant Client BasicもしくはBasic Lightパッケージ)をPATHもしくはLD_LIBRARY_PATH(またはそれに相当するもの)に通す必要があります。
Oracle Instant Client
http://www.oracle.com/technetwork/database/features/instant-client/
macOSをご利用の場合、Oracle Clientライブラリを~/libもしくは/usr/local/libに配置する必要があります。ODPI-Cを利用するとインストールが少々簡単になります。OracleのHeaderファイルはもう必要ありません。OCI_LIB_DIRとOCI_INC_DIRという環境変数は不要になっています。C++11をサポートするコンパイラ、Python 2.7は必要ですが、node-oracledbバイナリ1個だけでOracle Client 11.2、12.1、12.2で動作し、node-oracledbビルドをマシン間でコピーする際の移植性が向上しています。 古いクライアント・ライブラリがサポートしていない新しいOracle Databaseの機能を使用しようとすると、ランタイム・エラーが発生するため、デプロイメント環境に似た環境でテストを行ってください。
このリリースにおけるその他の変更は以下の通りです。
  • Lob.close()close()メソッドの非同期版ではなく、LOBを即座に無効にします。そのため、他のメソッド呼び出しは全て無効になります。
  • Version 1で、LOB、ResultSetまたはその他のデータベース操作を実行中に接続を閉じようとした場合、この正しくないアプリケーション・ロジックの結果NJS-030、NJS-031またはNJS-032の「接続を解放できません」というエラーが発生していました。Version 2では接続を閉じることができますが、開いている接続に依存する操作は失敗します。
  • 一部のNJSおよびDPIのエラーメッセージと番号が変更されました。これは特に、ODPI-C使用によるDPIエラーに当てはまります。
  • 現在、Node.js 4、6、および8と互換性があります。
  • (Stringとして)カラム型LONGと(Bufferとして)LONG RAWを取得できるようになりました。これらの型のストリーミングはサポートされていないため、Node.jsとV8のメモリ制限に達すると、DBに格納された値を完全に取得できない場合があります。ストリーミングできるLOBを使用するようにアプリケーションを変換する必要があります。
  • TIMESTAMP WITH TIME ZONE日付型のサポートが追加されました。これらは、LOCAL TIME ZONEを使用してnode-oracledb内のDateオブジェクトにマッピングされます。TIME ZONEコンポーネントは、Node.jsのDateオブジェクトでは使用できません。
  • ROWIDのサポートが追加されました。明示的なfetchAsStringは必要なくなりました。データはデフォルトでStringとして取得します。
  • Added support for UROWIDのサポートが追加されました。データはStringとして取得します。
  • NCHAR 列および NVARCHAR2 列のクエリがサポートされました。データベース文字セットおよびデータベースの各国語文字セットによってはDMLのバインディングでデータを正しく挿入できないことがあります。
  • NCLOB 列のクエリがサポートされるようになりました。NCLOB データをストリームもしくはStringとして取得できます。データベース文字セットおよびデータベースの各国語文字セットによってはDMLのバインディングでデータを正しく挿入できないことがあります。
  • LOB fetchAsString およびfetchAsBuffer クエリ、LOBバインドにおけるサイズ制限がなくなりました。Node.jsおよびV8のメモリ制限ゆえに一度に大きなLOBを操作できないのは今まで通りです。V1では11.2クライアントライブラリを使ってnode-oracledbと紐付けたユーザーにのみ制限が影響しました。
  • エラーを生成するステートメントを、ステートメント・キャッシュから削除するようになりました。表定義が変更されている間に実行されているアプリケーションは、古くなったキャッシュエントリのために、使用不能なSQL文で終わらなくなっています。アプリケーションはまだエラーが発生することがありますが、それをトリガーにして無効なキャッシュエントリを削除し、以降の実行が成功するようにします。ODPI-Cには、いまの説明よりもずっと優れた方法でやる仕組みが備わっていますが、お尋ねになると、退屈させることになるかもしれません。もしくはODPI-Cのソースコードをチェックすることができます。
    ODPI-Cソースコード(odpi/src/dpiStmt.c)
    https://github.com/oracle/odpi/blob/v2.0.0-rc.1/src/dpiStmt.c#L535-L536
    ご注意いただきたいのは、Oracleのベスト・プラクティスは、アプリケーション実行中に決して表定義を変更しない、ということです。いくつかのテストフレームワークが表定義を変更することを知っていますが。。
これらの改善はすべて、ODPI-Cが基礎部分を取り扱ってくれているおかげです。ODPI-Cの使用は、Node.jsに公開できる数多くのものを既にサポートしているので、将来の機能のための大きな飛躍的進展といえます。ODPI-Cプロジェクトは、以前はnode-oracledbだけが使用するDPI層の拡張でしたが、現在では、ODPI-CはPython cx_Oracle 6で使用されており、他のさまざまなプロジェクトで使用されてきています。
node-oracledb DPI Layer Extension
https://github.com/oracle/node-oracledb/tree/v1.13.1/src/dpi
Python interface to Oracle Database conforming to the Python DB API 2.0 specification
https://github.com/oracle/python-cx_Oracle
たとえば、Tamás Gulácsiは、ODPI-Cを使用するGoドライバを開発してきました(彼のブランチをチェックしてください)。
v5 with ODPI ?
https://github.com/rana/ora/issues/203
An Oracle database driver for the Go programming language.
https://github.com/rana/ora/tree/dpi
Kubo TakehiroもRust以外のプログラミング言語の選択を決める前に、Oracle Rustドライバの開発を開始しました!
Oracle driver for Rust
https://github.com/kubo/rust-oracle-wip
我々が表明しているnode-oracledbの計画では、node-oracledb 1.xのメンテナンスはNode 4のEoLにあわせ2018年4月1日で終了します。そのため、node-oracledb 2.0.13-Developmentのテストを開始します。
Node-oracledb 1.x and 2.x: Plans for 2017
https://github.com/oracle/node-oracledb/issues/601

[Docker] Announcing the release of Docker 17.03 CE

$
0
0
原文はこちら。
https://blogs.oracle.com/linux/announcing-the-release-of-docker-1703-ce

Docker 17.03 CE (Community Edition) for Oracle Linux 7のリリースを発表できうれしく思っています。
Dockerを使うとOracle LinuxシステムやDockerをサポートする他のOSとの間でアプリケーションの作成・配布が可能です。Dockerは、アプリケーションのパッケージ、実行を司るDocker Engineと、Software-as-a-Service (SaaS) クラウドでアプリケーションを共有するDocker HubやDocker Storeから構成されています。

Important

Docker 17.03 CE以後のバージョンはOracle Linux 7 (x86_64)でのみ動作します。Oracle Linux 6におけるDockerの最終リリースは1.12.6です。

Notable Updates

アップストリームのDockerリリースサイクルを変更に伴い、新しいバージョンスキームに変わっています。日付変数(YY.MM)をバージョン名に使用し、アップストリームバージョンのリリース時期がわかるようになっています。
Dockerのアップストリームのデフォルトストレージドライバが、devicemapperからoverlay2に変更されました。この変更により、-n ftype =1オプションを有効にして作成されていないXFS形式のファイルシステムを使用しているシステムで問題が発生する可能性があります。XFSをファイルシステムとして選択した場合、Oracle Linux 7のルートパーティションは自動的に-n ftype=0でフォーマットされるため、Oracleはdevicemapperを使うようデフォルトストレージドライバを戻し、Dockerを新規インストールシステムですぐに使えるようにしています。
現在overlay2ストレージドライバをお使いの場合、アップグレード時にストレージの移行が必要かどうかを判断するため、アップグレードの前に、Oracle Linux 7 Docker User's GuideのUpgrading Dockerの章をチェックしてください。
Oracle® Linux 7Docker User's Guide
https://docs.oracle.com/cd/E52668_01/E87205/html/index.html
2.1 Upgrading Docker
https://docs.oracle.com/cd/E52668_01/E87205/html/docker_install_upgrade_upgrade.html
overlay2ストレージドライバを使っている場合、SELinuxのEnforcingモードをサポートしませんので、Permissiveモードへの変更もしくはSELinuxを無効にしてください。
Docker Swarmの機能をTechnology Previewとして提供します。

Resources

Oracle LinuxへのDockerのインストールやアップグレードに関する詳細は、Oracle Linux 7 Docker User's Guideをご覧ください。
Oracle® Linux 7Docker User's Guide
https://docs.oracle.com/cd/E52668_01/E87205/html/index.html
Oracle製品はDockerイメージとしてOracle Container Registryからご利用いただけます。
Oracle Container Registry
https://container-registry.oracle.com/

[Database] Database Application Development VirtualBox VM Scripts Now on GitHub

$
0
0
原文はこちら。
https://blogs.oracle.com/developers/database-appdev-vm-scripts-on-github

Oracle Databaseを含む弊社の人気のある開発ツールを学びたいと思っている、データベース開発者やエンタープライズアプリケーション開発者の方々は、Database Application Virtual Applicanceを長年にわたって利用されてきました。このDatabase Application Virtual Applicanceはもっとも多くダウンロードされているものの一つです。

関連コンテンツ

このVirtualBox Applianceを使って、Oracle REST Data ServicesやDocker上でデータベースを実行することができます。
Oracle VM VirtualBox
https://www.virtualbox.org/
Oracle REST Data Services (ORDS)
http://www.oracle.com/technetwork/developer-tools/rest-data-services/overview/index.html
Docker Store
https://store.docker.com/search?certification_status=certified&q=oracle&source=verified&type=image 

さらに、このイメージにはデータベース開発・設計を学ぶためのハンズオンコンテンツが含まれています。このVirtual ApplianceはOTNから無料でダウンロードできます。
Database Virtual Box Appliance / Virtual Machine
http://www.oracle.com/technetwork/database/enterprise-edition/databaseappdev-vm-161299.html

Source Available on GitHub

さらに、開発者の方々が自信のVirtualBox Applianceをソースからビルドできるようになりました。仮想環境をご自身のニーズにあうようカスタマイズすることができます。GitHubプロジェクトのdb-appdev-vmのリリースを発表できることをうれしく思っています。ここで、Database Application Applianceのビルドに必要なツールは全てPackerで入手できます。
Database Application Development Virtual Machine 
https://github.com/oracle/db-appdev-vm
Packer
https://www.packer.io/ 
このプロジェクトにはセットアップ手順とOracle Linuxサーバの構築、Oracle Database 12cR2や開発ツールおよびハンズオンコンテンツをインストールするためのインストールスクリプトが含まれています。これらのスクリプトを構築および拡張し、新しいアイデアや機能拡張に貢献していただければと思います。
この仮想マシンアプライアンスは以下のソフトウェアで構成されています。
  • Oracle Linux 7
  • Oracle Database 12c Release 2 Enterprise Edition (12.2.0.1 Linux x86-64)
  • Oracle SQL Developer 4.2 
  • Oracle SQL Developer Data Modeler 4.2
  • Oracle REST Data Services 3.0.9
  • Oracle Application Express 5.1
  • Oracle XML DB
是非チェックしてください。

[Docker, Cloud] Three New Open Source Container Utilities

$
0
0
原文はこちら。
https://blogs.oracle.com/developers/three-new-open-source-container-utilities

コンテナは以前に比べて人気があり、ここOracleでも、数多くのクラウドサービスのためにコンテナを使っています。本番環境でコンテナを準備する際に、コンテナの構築および運用が楽になるようなツールを開発しました。本日、これらのツールをオープンソースとして公開し、皆さんにお使いいただけるようにしたことを発表でき、うれしく思います。これらのツールはそれぞれ、Smith、Crashcart、Railcarといい、OracleのGitHubページからご利用いただけます。以下で説明します。
Smith
https://github.com/oracle/smith
Crashart
https://github.com/oracle/crashcart
Railcar
https://github.com/oracle/railcar

Smith -- Secure Microcontainer Builder

私たちは、これまでのDockerの利用で運用上の問題に遭遇しました。Smithは、整合性がありセキュアなビルドを実現することでこれらの問題を解決するツールです。rpmやyumリポジトリ、あるいは "fat"なDockerコンテナからマイクロコンテナ(Microcontainer)をビルドします。
The Microcontainer Manifesto And The Right Tool for the Job
http://blogs.oracle.com/developers/the-microcontainer-manifesto
マイクロコンテナの利用に行き着いた運用上の課題についての詳細は、The Microcontainer Manifestoをご覧ください。

Crashcart -- Microcontainer Debugging Tool

コンテナを本番環境での利用のために最小限にすると、ツールがなければ運用管理者が発生した問題を診断、修復することが難しくなります。ほとんどのデバッグはホストから実施できますが、時にはコンテナが参照しているがゆえに、ファイルシステムへのアクセスが必要な場合があります。Crashcartはこうしたユースケースのために作成されました。Crashcartを使うと、バイナリを実行中のコンテナにロードすることができるので、何がうまくいっていないのかを把握できます。バイナリのサイドローディングが困難な理由とCrashcartがその課題を解決するしくみは、以下のエントリをご覧ください。
Hardcore Container Debugging
https://blogs.oracle.com/developers/hardcore-container-debugging

Railcar -- Alternative Container Runtime

Goはコンテナランタイム用の言語としてはいま一つという感じです。問題を理解する上で、weave worksによるブログエントリをご覧ください。
Linux Namespaces And Go Don't Mix
https://www.weave.works/blog/linux-namespaces-and-go-don-t-mix 
この問題などを回避するために、runc(Open Container Initiative Runtime Specificationのデフォルト実装)には、goランタイムが開始する前に実行される、Cで記述されたコードがあります。
CLI tool for spawning and running containers according to the OCI specification 
https://github.com/opencontainers/runc
Goはすばらしい言語ですが、スレッドを厳密に制御し、大量のシステムコールを作成する必要のある小さなシステムユーティリティ向けには、より良い選択肢があります。Rustはcのような低レベルの制御を提供しますが、メモリセーフで、バグや脆弱性のあるクラス全体を回避します。railcarの開発に関する詳細情報は、以下のエントリをご覧ください。
Building a Container Runtime in Rust
https://blogs.oracle.com/developers/building-a-container-runtime-in-rust

[Linux] CVE-2017-1000364

$
0
0
原文はこちら。
https://blogs.oracle.com/wim/cve-2017-1000364

多くの方々がCVE-2017-1000364について聞いたり読んだりされていると思います。まだの方は、以下のURLに情報が上がっています。
All posts tagged with CVE-2017-1000364 (Qualy's Blog)
https://blog.qualys.com/tag/cve-2017-1000364
CVE-2017-1000364 Detail
https://nvd.nist.gov/vuln/detail/CVE-2017-1000364
Linux Kernel CVE-2017-1000364 Local Memory Corruption Vulnerability
http://www.securityfocus.com/bid/99130
問題はLinuxのStack Guard Pageのサイズで発見されました。具体的には4kサイズのStack Guard Pageが十分に大きくないためにStack Guard Pageを飛び越えることがあります(バイパスしてしまいます)。これはLinux Kernelバージョン4.11.5以前に影響します(Stack Guard Pageは2010年に導入されました)。
このCVEは9.8という非常に高いCVSSスコアです。
このCVEに対処するため、Oracle Linux用のパッケージ・リリースが数多くあります。
CVE-2017-1000366 (アップデートされたglibc)
https://linux.oracle.com/cve/CVE-2017-1000366.html
アップデートされたカーネル(CVE-2017-1000364)
https://linux.oracle.com/cve/CVE-2017-1000364.html
とても重要な追加情報として、Kspliceを使うとオンラインで修正を適用することができます。そのため、Oracle Linuxのサポートサブスクリプションをお持ちのお客様は、uptrack-upgradeを実行中のカーネルで実行するだけでよいのです。再起動は必要ありません。
# uptrack-upgrade
The following steps will be taken:
Install [8cpcuyra] CVE-2017-1000364: Increase stack guard size to 1 MiB.

Go ahead [y/N]? y
Installing [8cpcuyra] CVE-2017-1000364: Increase stack guard size to 1 MiB.
Your kernel is fully up to date.
Effective kernel version is 4.1.12-94.3.7.el7uek

[Java, Docker] GlassFish Docker Images – Update

$
0
0
原文はこちら。
https://blogs.oracle.com/theaquarium/glassfish-docker-images-%e2%80%93-update

GlassFishのDokerイメージをアップデートしました。DockerHubからご利用いただけます。以下にアップデートのポイントをご紹介します。
GlassFish Java EE Application Server on Oracle Linux and OpenJDK
https://hub.docker.com/r/oracle/glassfish

GlassFish 4.1.2 Docker Images

GlassFishの最新リリースは4.1.2です。oracle/glassfishのlatestタグはoracle/glassfish:4.1.2を指しています。GlassFish 4.1.2 full profileのDockerイメージは以下の方法でダウンロードできます。
docker pull oracle/glassfish
もしくは
docker pull oracle/glassfish:4.1.2
GlassFish 4.1.2 web profileのDockerイメージは以下の方法でダウンロードできます。
docker pull oracle/glassfish:4.1.2-web

GlassFish 5.0 Nightly Docker Images 

以前のGlassFish 5.0 nightly DockerイメージはDockerHubの'glassfish'という組織の下にありました。
GlassFish 5.0 Nightly Builds on Docker Container (glassfish/*)
https://hub.docker.com/r/glassfish/nightly/
同じ組織の下でGlassFishの全てのDockerイメージを維持管理するため、'glassfish'から 'oracle'という組織にDockerイメージを移動しました。
GlassFish Java EE Application Server on Oracle Linux and OpenJDK (oracle/*)
https://hub.docker.com/r/oracle/glassfish/
今後glassfish/nightlyというDockerイメージはメンテナンスしませんので、使わないでください。そのかわりに、GlassFish 5.0のnightlyイメージはoracle/glassfish:nightly (web profileをご入用の場合oracle/glassfish:nightly-web ) を使ってください。
GlassFish 5.0 full profile nightly Dockerイメージは以下の方法でダウンロードできます。
docker pull oracle/glassfish:nightly
GlassFish 5.0 web profile nightly Dockerイメージは以下の方法でダウンロードできます。
docker pull oracle/glassfish:nightly-web

GlassFish Admin Password Handling

以前のadminユーザーのパスワードは、oracle/glassfish Dockerイメージのデフォルトの値('glassfish'がデフォルトのパスワード)でしたが、これはセキュリティ上の問題がありました。そのため、実行時にorchestratorで提供するパスワードを使うようにイメージを更新しました。orchestratorがdocker runを実行時にパスワードを提供しない場合、実行時にパスワードを自動生成します。

Orchestratorで提供するパスワード
docker run -ti -e ADMIN_PASSWORD=<your-secret-password> -p 4848:4848 -p 8080:8080 -d oracle/glassfish:4.1.2
自動生成するパスワード
docker run -ti -p 4848:4848 -p 8080:8080 -d oracle/glassfish:4.1.2
自動生成パスワードは以下のdocker logコマンドを実行して取得できます。
docker logs <CONTAINER> | grep "GENERATED ADMIN PASSWORD"
この変更はGlassFishイメージの全てのタグ(4.1.1、4.1.1-web、4.1.2、4.1.2-web、nightly、nightly-web、latest)に実施されています。

Updated Base Image

以前のGlassFishイメージはoraclelinux:latest (225MB) を使っていましたが、現在のGlassFishイメージでは、oraclelinux:7-slim (114MB)をベースイメージとして使うようにした結果、より軽量になっています。oracle/glassfishイメージの全てのタグに対してこの変更を実施しています。

JDK Version used in GlassFish docker images

ImageJDK Version
oracle/glassfish:latestopenjdk 1.7.0_141
oracle/glassfish:4.1.1openjdk 1.7.0_141
oracle/glassfish:4.1.2openjdk 1.7.0_141
oracle/glassfish:4.1.1-webopenjdk 1.7.0_141
oracle/glassfish:4.1.2-webopenjdk 1.7.0_141
oracle/glassfish:nightlyopenjdk 1.8.0_131
oracle/glassfish: nightly-webopenjdk 1.8.0_131

Docker Build Scripts

oracle/glassfish Docker イメージの全てのタグに対応するDockerビルドスクリプトは以下のURLからご利用いただけます。
スクリプトおよびDockerfile
https://github.com/oracle/docker-images/tree/master/GlassFish
是非お試しの上、フィードバックをお寄せください。

[Docker] Building a Container Runtime in Rust

$
0
0
原文はこちら。
https://blogs.oracle.com/developers/building-a-container-runtime-in-rust

コンテナエコシステムは拡大を続けており、プロプライエタリな実装が徐々にオープンスタンダードなものに取って代わっています。オープンコンテナイニシアティブ(OCI)から出ている最も重要な標準の一つが、OCI Runtime Specificationで、代替コンテナ実行環境を開発することを許容するものです。
OCI Runtime Specification
https://github.com/opencontainers/runtime-spec
ランタイムの選択は、イノベーションとより良い実装につながります。Oracleのコンテナ開発の一環として、railcarと呼ばれるrustで動作するランタイムを実装することにしました。
RailCar: Rust implementation of oci-runtime
https://github.com/oracle/railcar
以下でランタイムの開発、直面した課題、および教訓について詳しく説明します。

Related Content

Why Rust?

今日では、ほぼすべてのコンテナユーティリティがCまたはGoで記述されています。CはLinuxカーネルとやりとりするのに最適ですが、セキュリティ上の問題があります。Goは、開発スピードやメモリの安全性の面で優れていますが、名前空間との相互作用に問題を生じるいくつかの制限があります。
Linux Namespaces And Go Don't Mix
https://www.weave.works/blog/linux-namespaces-and-go-don-t-mix
Rustはこれらの2つの言語の長所を兼ね備えています。つまり、メモリの安全性とより高いレベルのプリミティブを備えていますが、スレッド管理に対する低レベルの制御を犠牲にしないため、名前空間を適切に処理できます。これはコンテナユーティリティにとってよい選択であり、我々はRustコミュニティとコンテナコミュニティが今後もっと協力し合うことを期待しています。

Implementation Challenges

Forking

Linuxの名前空間と正確に相互作用することは極めて困難です。ユーザーおよびpidの名前空間を適切に入力するためには、大量のforkや同期が必要で、非常にいらだたしいものです。組み合わせ可能なlimited isolation primitivesにメリットがあるとはいえ、確実にjailやzoneのようなよりシンプルなモデルを待望されることでしょう。
Namespaces in operation, part 5: User namespaces
https://lwn.net/Articles/532593/
Namespaces in operation, part 3: PID namespaces
https://lwn.net/Articles/531419/
Setting the Record Straight: containers vs. Zones vs. Jails vs. VMs
https://blog.jessfraz.com/post/containers-zones-jails-vms/

Complexity and Debugability

仕様の実装はかなり簡単ですが、バックエンドをDockerの背後で動作させることは、かなり大変です。具体的には、様々なプロセスが関わって、問題になっていることを見ています。`docker run`のようなコマンドでは、
docker client - > dockerd - > containerd - > containerd-shim - > runtime
のように呼び出されます。事態がうまくいかないとき、何がうまくいかなかったのか、その理由は不明です。containerdによるランタイムに対するShell呼び出しで、containerdがクラッシュすることがあり、その場合dockerdがcontainerdを再起動させるため、実際のエラーが記録されないまま無限ループに陥ります。

Incomplete Spec

最も不満なことの一つが、仕様に記載の通りに実装するだけでは不十分で、Dockerの代替バックエンドとはなり得ない、ということでした。その他にいくつか作業が必要でした。例えば、containerdが<runtime> psもしくは<runtime> statsを呼び出そうとした場合、これらの操作はruncがサポートしますが、仕様に言及はありません。

Bugs

containerd/runcが正しく仕様に従っていないことがあります。例えば、仕様ではコンテナ削除後にdeleteを呼び出すとエラーを返すはずですが、テストでは、containerdがdeleteを2回呼び出し、runcは2回のdeleteを受け付けることを明確に示していました。runcはインスタンスが完全に削除された後エラーを返すため、最初のdeleteは実際に何も削除しないと想定し、2度目の呼び出しをします。この振る舞いは、適切に最初の呼び出しで全てを削除する別のランタイムでは問題を引き起こします。

Misfeatures

仕様のいくつかの部分は少し過剰のように思えます。おそらくまだ仕様策定後時間が経っていないからでしょう。困難な実装の1つとして、起動前(prestart)、起動後(poststart)のイベントフックでした。これらは、run(実行)コマンドが使用されていた場合には非常に便利でしたが、仕様が変わって create(作成)、start(開始)、stop(停止)コマンドになったため、この手の作業をランタイムの外部で行うことができます。ランタイムは単にコンテナ化に集中することになるため、ランタイムが実行するフックは、関心の分離(Separation of Concerns)に違反します。

Differences From Runc

Railcarの動きは、デフォルトのランタイムとは少し異なり、常にinitプロセスを作成します。
CLI tool for spawning and running containers according to the OCI specification
https://github.com/opencontainers/runc
pid名前空間にinitプロセスがないと、奇妙な問題が発生します。
The Curious Case of Pid Namespaces
https://hackernoon.com/the-curious-case-of-pid-namespaces-1ce86b6bc900
そのため、新しいランタイムが提供する機会を利用して、別のオプションを試すことにしました。この機能が提供する一貫性を気に入っていますが、擬似端末が使用されていないときに標準出力と標準エラー出力の周りで予期しない動作が発生することがあります。

Lessons Learned

The Rust Language

このようなプロジェクトでは、Rustは優れた選択であることがわかりました。Goランタイムが起動する前のruncにとって必要な不快なCコードの注入は、常に迷惑なものでした。Rustは、1つの言語でRailcarの全体を実装するのに十分な柔軟性がありました。また、必要に応じて静的なバイナリを構築することもできるのです。

言語はまだ枯れてはいませんし、もっと多くのライブラリのサポートを使うこともできますが、やりたいことを実現するにあたって必要なものの大部分はかなり簡単に実現できました。安全でないコードの利用を最小限に抑え、コードのメモリ安全性に関して信頼を得ました。

Fast Container Startup

代替ランタイムに対する我々のゴールの一つが、コンテナ起動時間を短縮する方法を確認する、というものでした。Rust実装はわずかにGo実装よりも速いのですが、コンテナ起動時間(およそロードしないシステムで150msec)の半分以上は実はカーネルのロック待ちということに驚きました。

Off-CPUプロファイリング手法を使って、ロック待ちの主犯はcgroupの作成と名前空間の作成であることがわかりました。これはつまり、本当に高速な起動のためには、名前空間とcgroupをあらかじめ作成しておき、起動時にそれらを特化するだけにとどめる必要があります。
Off-CPU Flame Graphs
http://www.brendangregg.com/FlameGraphs/offcpuflamegraphs.html
このような方法をサポートするためには、ランタイム仕様の作成/開始フローへのいくつかの変更が必要ですが、検討する価値はあります。ネットワーク名前空間とcgroupがあらかじめ作成されている場合、起動時間は10ms以下です。

Future Improvements

railcar startでinitプロセスの標準出力および標準エラー出力へのアクセスが可能になれば、runcとの互換性が向上します。現時点では、ターミナル無しでDocker内でrailcarを実行すると、ユーザープロセスからの標準出力と標準エラー出力へのアクセスはできませんので、railcarが実装していないstatsコマンドのようなruncの他の機能が非常に有用です。仕様のより新しいバージョンに対する自動テストはもう一つの価値の追加になることでしょう。
一般に、railarはまだ幅広いシナリオで使われてはいませんので、railcarを試し、発生する問題解決の支援をしてくださるコミュニティの皆様に感謝しています。railcarがcri-oを介してKubernatesのバックエンドとしても利用されることになればすばらしいことでしょう。
Kubernetes | Production-Grade Container Orchestration
https://kubernetes.io/
Open Container Initiative-based implementation of Kubernetes Container Runtime Interface
https://github.com/kubernetes-incubator/cri-o

Conclusion

全体として、別のランタイムの実装は非常に価値ある作業でした。ランタイムがコミュニティから注目を集め、有用なコンテナ化の選択肢が存在し続け、実験と相互交流が促進されることを願っています。自由にGitHubリポジトリをクローンし、問題がありましたらお知らせください。
railcar Issue Tracking
https://github.com/oracle/railcar/issues

[Docker] The Microcontainer Manifesto and the Right Tool for the Job

$
0
0
原文はこちら。
https://blogs.oracle.com/developers/the-microcontainer-manifesto

コンテナの人気が、ここ数年で劇的に高まっています。コンテナはパッケージマネージャと構成管理の両方を置き換えるために使用されてきました。コンテナの標準的なビルドプロセスは開発者にとっては理想的ですが、残念ながら、結果として得られるコンテナイメージにより、オペレータの仕事がより困難になっています。

Related Content

Oraccleではクラウドサービスの構築時に、コンテナの恩恵を受ける可能性のあるいくつかのサービスを特定しましたが、コンテナの安定性とセキュリティを確保する必要があります。本番利用でのコンテナ利用に慣れるため、コンテナの構築プロセスの変更が必要でした。構築プロセスの問題を分析した後、環境の安定性とセキュリティを劇的に改善したコンテナの構築および実行方法を開発しました。2年以上前にこのプロセスを開始して以来、コンテナの安定性とセキュリティは劇的に向上しました。

Problems Resulting from Docker Build

問題の多くは、Linux全体をコンテナイメージに入れるという作業から生じます。具体的には以下の通りです。

1. Large Images

長きにわたり、イメージ構築の標準的な方法は、 `FROM debian / jesse`で始まり、その結果、大きなサイズのイメージをダウンロードすることになりました。これは管理性のためだけにレイヤを必要としていました。 これは、alpine linuxへの切り替えによっていくらか改善されましたが、すべてのソフトウェアがalpine linux上に構築するのは簡単ではありません。 今日でも、最も人気のあるイメージの多くは1G以上のサイズです。

2. Privilege Escalation

Linuxのユーザー空間全体をアプリケーションデプロイメントアーティファクトにするという習慣は、アプリケーションのセキュリティ侵害は、特権昇格のための他の潜在的な攻撃手段を与えることを意味します。コンテナ内にアプリケーション以外のものを置かないことでよりセキュアになります。

3. Vulnerability Management

コンテナの最大のセキュリティ問題の1つは期限切れの依存関係です。コンテナはイミュータブル(不変)であって、パッケージマネージャを介して脆弱なソフトウェアを更新するソリューションはありません。つまり、ビルド時に実行する必要があります。標準ビルドプロセスでは、コンテナ内のどのファイルが実際に使用されているかが不明ゆえに、コンテナのアップデートが必要か否かを判断することが難しくなります。つまり、「アプリケーションがコンテナ内の脆弱なバージョンのOpen SSLを使用しているのか、それとも単に標準インストールの一部として含まれていたのか」が不明なのです。
これらのビルドの問題の多くは、コンテナシステムをリードすることによって既に解決済みです。マルチステージビルドや--squashオプションを追加すると、コンテナを操作する他の方法が提供されますが、今回さらに一歩すすめました。その内容についてコミュニティからどのようがあるかを知りたいと思っています。

Other Operational Changes

ビルドの問題に加え、オペレーション上の変更を実施して悩みを最小限にしました。これらはコンテナシステムやその機能の悪い部分というわけではありませんが、以下の点で成功しました。

1. No Layers

コンテナを使って数年後、Layerが運用上問題のある仕様であると判断しました。 開発時にあたっては、Layerは素晴らしい仕様です。ビルドプロセスの最後のいくつかのステップをキャッシュし、毎回イメージ全体をダウンロードしなくても新しいバージョンのコードを実行できるという点で素晴らしいものです。問題は、デプロイメント・イメージの複数のLayerが不必要な複雑さを意味する点です。最近追加されたdocker buildコマンドに--squashオプションが追加されたことで、他の人が同じことを発見したことを示しています。

2. User Namespaces

ユーザー名前空間は素晴らしいセキュリティ機能です。誰かが名前空間の分離を破って出た場合、ホストに対する権限のないユーザーに割り当てられます。一般に、ファイルシステムのユーザーの所有権が適切にマッピングされないため、ユーザーの名前空間を有効にすることは困難です。Dockerはしばらくこの件について取り組んできました。彼らは最近、すべてのコンテナに対して単一のユーザー名前空間を共有する機能を追加しましたが、設定変更が必要で、しかもその設定変更はほとんど利用されることはありません。各コンテナが独自のユーザー名前空間を持つことが理想的ですが、残念なことに、これには読み込み専用のイメージまたはファイルシステムIDのマッピングのためのカーネルサポートが必要です。

3. No Overlayfs

OverlayFS(およびその前身のUnionFS)は、本番環境での数多くの問題の原因となっています。同じイメージから多くのコンテナを起動している場合は、ソースイメージの各コンテナディレクトリへのコピーは膨大な領域を必要とするため、オーバーレイの目的は理にかなっています。私たちは将来的にOverlayFSを使いたいと思っていますが、これまで避けていた運用上の問題にぶつかりました。さらに、ファイルシステムIDをマップできないということは、一意のユーザー名前空間には役立たないことを意味します。

4. No Image Repository

イメージのダウンロードは、多くの問題の原因となっています。 ネットワークの問題、不適切なイメージ、Layerの破損で悩まされてきました。私たちは、帯域外でノードに必要なイメージをデプロイするだけで、より多くの運用上の成功を収めました。これにより、セキュリティ上の脆弱性が存在する場合に、すべてのノードが最新バージョンのイメージを持つようにすることもできます。
これらの機能を有効にするには、デプロイメント・アーティファクトを、手作業でデプロイするのに十分な小さい読み取り専用コンテナに縮小します。ファイルシステムは読み取り専用なので、ユーザーの名前空間を有効にしてレイヤーやオーバーレイを避けることができます。

The Solution: Microcontainers

本番環境でコンテナを使っている際に目の当たりにしたこうした問題を解決するため、microcotainerと呼ぶ新しいコンセプトを作成しました。注意いただきたいのは、これは新しいコンテナ形式ではなく、単によりよいセキュリティや安定性を可能にする、特定のコンテナ構築方法です。具体的にmicrocontainerとは
  • 単一の実行可能ファイルとその依存関係のみが含まれています(つまりShellとinitプロセスがありません)
  • 読み取り専用のルートファイルシステムで実行されます(書き込みはボリュームマウントによって分離されて処理されます)
  • ユーザーとグループのファイルシステムの所有権はありません(すべてが単一のユーザーによって所有され、読み取り可能です)
  • ファイルシステムのタイムスタンプや機能はありません
  • 再現可能に構築することができ、毎回同じイメージを生成します
これらの原則に加えて、microcontainerを実際に簡単に実践できるようにするいくつかのファイルロケーション規約(file location conventions)を採用しています。ソフトウェアパッケージは、さまざまな場所に構成ファイルをインストールし、他の場所にファイルを書き込みます。すべての一時ファイル(pidファイルのような)を/runディレクトリに入れ、すべての永続的な書き込み(ログファイルとデータファイル)を/writeディレクトリに入れます。コンテナごとに変更する必要のある設定ファイルを/readディレクトリに入れます。なお、設定ファイルはボリュームマウントかkubernetes configmapで変更できます。
これらの原則と規約を実装することで、運用上の頭痛につながる主要なセキュリティと安定性の問題のいくつかを解決することができます。

Building a Microcontainer

静的にリンクされたGoバイナリを構築し、ベースとしてスクラッチ(開発)を使用している場合は、すでにmicrocontainerを構築している可能性があります。他のソフトウェアでは、マイクロコンテナを構築するのが難しい場合があります。そのため、私たちはmicrocontainerを構築するために利用するsmithをオープンソース化しました。このツールを使って、yumリポジトリと(オプションで)rpmファイルからmicrocontainerを構築できます。
さらに、既存のDockerコンテナを「microize(訳注:microsizeのtypoだと思われます)」するために使用できるので、開発中はコンテナ構築にあたって開発者にとって便利なDockerのツールを使用し、実稼働環境に合わせてmicrocontainerに変換できます。smithは標準のoci形式でイメージを構築しますが、Dockerリポジトリからイメージをアップロード/ダウンロードすることもできます。

Practical Considerations

様々な方法でconfigファイルを/readに入れたり、出力ファイルを/writeに入れたりすることができます。コマンドラインパラメータで設定することもできますが、簡単な解決策の1つは、予想される場所を適切なディレクトリにシンボリックリンクを貼ることです。たとえば、/var/log/appnameを/write/logにシンボリックリンクを貼ることができます。
smithは実行可能ファイルのリンクされた依存関係を検出できますが、dlopenで開いたライブラリを自動的に拾い上げませんし、構成ファイルやデータファイルを自動的に取得しません。実際には、他のファイルをどのように含める必要があるかを把握するのは概してかなり簡単です。既存のアプリケーションをmicrocontainerにパッケージ化するのに、通常は1時間以上かかりません。最終的には、イメージがより安全で、他の技法を使って作成されたものよりも10倍も小さくなります。
多くのソフトウェアパッケージは、適切に機能するために基本的なユーティリティに依存しています。他のすべてのユーティリティ(bash、grep、awkなど)をマイクロコンテナに入れないことがベストですが、実行しようとしている実行可能ファイルが、実際には実際のアプリケーションを実行する前に環境設定を行うシェルスクリプトであることがあります。場合によっては、これらの依存関係を取り除くために必要な労力が大きすぎるため、これらのユーティリティのいくつかをコンテナに含めざるを得ないことがあります。一般に、すべてのルールは破られる可能性があります。実用的であることは常に良い考えです。コンテナに含めるすべてのものに正当な理由があることを確認してください。維持する必要があるものになるからです。

Running a Microcontainer

一意のユーザー名前空間でコンテナを実行するには、runcのようなものを使って手動で設定する必要がありますが、Dockerを直接使用して他のメリットも享受できます。Dockerはociイメージをインポートできないので、smithで構築されたmicrocontainerイメージをDocker HubのようなDockerリポジトリにプッシュしてから実行する必要があります。
microcontainerの利点をすべて享受するには、コンテナを読み取り専用モードで実行します。
docker run -ti --read-only --tmpfs /run -v /my/write/directory:/write my-microcontainer

Operations

microcontainerは、システムのセキュリティを向上させる優れた方法です。 smithを使ってビルドしている場合は、アプリケーション自体が変更された場合にのみコンテナのIDが変わります。つまり、自動ビルドを構成してコンテナの再デプロイの必要性を警告することができます。しかし、docker execコマンドを使ってアクセスできるコンテナ内にツールがないため、デバッグが難しいという欠点もあります。このため、デバッグに役立つcrashcartという別のツールもリリースしました。
CrashCart: sideload binaries into a running container
https://github.com/oracle/crashcart
Hardcore Container Debugging
https://blogs.oracle.com/developers/hardcore-container-debugging
Viewing all 760 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>