Amazon SESを使ってみた
AWSのアカウントはもっている前提で進めます。
メールアドレスの認証
初期の状態。「Verify a New Email Address」をクリックする。
eメールアドレスを追加します。
追加したアドレスに、次のようなタイトルのメールが来ます。 * Amazon SES Address Verification Request in region US West (Oregon)
メール中のリンクをクリックすることで、メールアドレスの検証が完了しました。
追加したアドレスのStatusがVerifiedに変わって居ます。
このEmailの検証依頼を、APIから行うこともできるので、利用者に送信メールアドレスを登録させて、自前のサービスに組み込むこともできそうです。 VerifyEmailIdentity - Amazon Simple Email Service
Consoleからのメールの送信
使用する送信元を選択して、Send a Test Emailを選択します。
この状態ではSandboxなので、認証済みの送信先にしか遅れません。ここでは送信元と同じアドレスにします。
このようなメールを受信しました。amazonses経由と表示されています。DKIMの設定を行うことで、自ドメインから遅れるようなので後から試します。
コンソール側で見ると送信済み1件になってますね!
Amazon SES APIを使用したメール送信
次はAPIを使ってメールの送信を行ってみたいと思います。
2015年夏のAndroidのツール関連、個人的に気になるポイント
Android Mの名前はマカロンとか、M&Mとか噂になりましたけど、Marshmallowになりましたね。
Android Studioはバージョン1.3が安定版としてリリースされました。
Get your hands on Android Studio 1.3 | Android Developers Blog
Data Binding
これまではサードパーティのライブラリを使用していましたが、公式でサポートされました。 Data Bindingを使うことで、画面と、エンティティの間をひたすら値をコピーするしょうもない作業をする必要がなくなります。
Data Binding Guide | Android Developers
NDK
お試してきな感じで、Android Studio 1.3でサポートされているようです。 丁度、NDKを使用するプロジェクトが始まっているのですが、Qiitaとかで苦労されている人が多そうだったので、Android Studioでの開発は見送りました。
参考
Android Developers Blog 公式発表もここから発信されることが多いみたいです。
Android Developers マニュアル、サンプル、ガイドライン。
Mule ESB 3.7 GETのQuery Parameterを解析してログに出すサンプル
'http://localhost:8082/4apppot/output_queries?name1=test1&name2=test2' こういうURLでアクセスしたときに、Query Parameterを解析するサンプルです。
"#[message.inboundProperties.'http.query.params'.name1]"というキーを指定して取得することもできますが、動的にQueryを解析したい場合には、固定のキーを書くことができないこともあると思います。
Muleアプリのサンプル
実行時のログ
'http://localhost:8082/4apppot/output_queries?name1=test1&name2=test2'にアクセスしたときに、次のログが出力されました。1行が長くて見にくいので、大事なところだけ編集しています。
About to echo ParameterMap{[name1=[test1], name2=[test2]]} payload(1): name2=test2 payload(1).key: name2 payload(1).value: test2 payload(2): name1=test1 payload(2).key: name1 payload(2).value: test1
サンプル解説
foreachでループ
Queryの数分ループします。 '#[counter]'で、ループの回数を取れます。0じゃ無くて、1からスタートするので注意!
entrySet()
このサンプルのポイントは、foreachのcollectionに指定している"#[message.inboundProperties.'http.query.params'.entrySet()]"
。
25行目で、#[message.inboundProperties.'http.query.params']
の値をログに出していますが、その時の値は
ParameterMap{[name1=[test1], name2=[test2]]}
。つまりMapです。entrySet()を使うことで、payload変数にはKey、Valueのセットが入ります。
後はpayload.keyでQueryのKeyへ、payload.valueでQueryのValueへアクセスできます。
Mule ESB 3.7のエラーハンドリング
Muleではフローの実行中にエラーが発生したときのエラーハンドリングの仕組みを持っています。
いくつかの例外のタイプが用意されています。これらの例外ハンドリングの定義を含んだ親Flowを実行中に発生した例外が対象です。
- Catch exception strategy 例外ハンドリングができますが、トランザクションはコミットされます。
- Rollback exception strategy 例外ハンドリングができますが、トランザクションはロールバックされます。
- Reference exception strategy
- Choice exception strategy
この中で実案件では、Choice exceptionの理解は必須でかなと思います。 発生したエラーの内容に合わせて、実装するハンドリングを切り替えます。 実際のエラーハンドリングはCatch exception strategyや、Rollback exception strategyで書いていく。
構造を単純に書くとこんな感じ。
<flow> <リクエストの受取/> <メッセージ変換など/> <連携先の呼び出し/> <応答メッセージの編集/> <choice-exception-strategy> <例外Xが起こったときのハンドリング/> <例外Yが起こったときのハンドリング/> </choice-exception-strategy> </flow>
実際のサンプルです。
例えば、上の定義だと、データベースの接続ができなかった場合は次のエラーが発生しますが、その時、「500 Internal Server Error」をクライアントに返します。
org.mule.module.db.internal.domain.connection.ConnectionCreationException: java.sql.SQLException: Cannot get connection for URL
Select文のWhere句に使用する値をQuery Parameterから取得しています。そこに不正な文字列が使用された場合などにjava.sql.SQLSyntaxErrorException
が発生しますが、「400 Bad Request」をクライアントに返します。
これでよく分からないエラーメッセージが返ってくるよりも ぐっと、使い易いWebサービスになりました。
参照情報
マニュアル
Error Handling - Current Mule Documentation
公式サンプル
JenkinsからWildFlyへのリモートデプロイ(pom.xmlの更新)
前回は、Jenkinsサーバーが乗っているDockerコンテナから、WildFlyが動作しているアプリケーションサーバー用Dockerコンテナへのコンテナ間接続をやりました。 begirama.hatenablog.com
JenkinsからWildFlyへのリモートデプロイはWildFly Maven Pluginというのがあって、MavenからWildFlyへのデプロイ、アンデプロイ、インスタンスの起動停止が行えるようです。
WildFly Maven Plugin - Plugin Documentation
deployに関する詳細なリファレンスは下記。 WildFly Maven Plugin - wildfly:deploy
公式サイトではないですが、リモートサーバーへデプロイする際のpom.xmlの例はこちら。 Configuring Maven WildFly plugin
実際のpom.xmlのデプロイ部分はこんな感じ。
<plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>1.1.0.Alpha1</version> <executions> <execution> <id>deploy</id> <phase>install</phase> <goals> <goal>deploy</goal> </goals> <configuration> <hostname>apppot_runtime1.7</hostname> <port>9990</port> <name>apppot-1.7-ci-jenkins.war</name> <username>{username}</username> <password>{password}</password> <filename>apppot-1.7-ci-jenkins.war</filename> </configuration> </execution> </executions> </plugin>
deployタスクのconfigurationとして、次を指定しています。
- hostname: Docker Linkした結果、hostsに定義されたホスト名を指定します。
apppot_runtime1.7
- port: WildFlyの管理ポートを指定。アプリケーションサーバーコンテナで、管理ポートをexposeしています
- name: デプロイする名前。warの拡張子を付けてないとだめ。付けてない場合、デプロイタスク自体は成功するけど、WildFly側でいろいろ認識されていなくて動かなかった。特にエラーもでないから調査に時間かかった。
- username: WildFlyにログインするためのアカウント
- password: WildFlyにログインするためのパスワード
- filename: デプロイするwarファイルを指定しています
すごくはまったのは、[ERROR] JBREM000200: Remote connection failed: javax.security.sasl.SaslException: Authentication failed: the server presented no authentication mechanisms
のエラー。
いろなサイトを参考にして、nameだけ指定して、usernameは使っていませんでした。この時に、上のエラーが発生していました。逆にusernameのみを指定しても同じエラーが発生しました。結局、usernameとnameの両方を指定することで、解消しました。参考にしたサイトの人たちはなんで成功していたんだろう・・・。
認証で、こけると何でもこのエラーになるみたいです。
2015/08/21追記
WildFlyの古いバージョンだと、ネイティブ用のポートを使ってデプロイしていて、それだとusernameが不要のようです。 最新のWildFlyだと管理ポートのプロトコルはHTTPで、その場合、usernameが必要なようです。 それで古い記事を参考にしていると駄目だったんだな。
JenkinsからWildFlyへのリモートデプロイ(DockerコンテナのLink)
自社製品のAppPotの開発、運用環境は次のような構成になっています。
- 自社クラウド本番環境:クラウド運用しているバージョンのみ
- 自社クラウドテスト環境:クラウド運用しているバージョンのみ
- 自社クラウド開発環境:クラウド運用しているバージョンのみ
- 自社CI環境:製品バージョンごとに存在
- 受託プロジェクト開発開発:プロジェクトごとに存在
バージョンごとに環境を立てるのは大変なので、自社CI環境と受託プロジェクト開発環境はDockerコンテナ上で運用しています。常にすごい負荷がかかっているわけではないので、小規模なさくらインターネットのサーバーで3〜5つくらいのコンテナが動作しています。
このうち、CI環境の一部だけはJenkinsを使ったビルド、デプロイ、テストのプロセスが自動で回っています。この一部というのは、Jenkinsと同居しているアプリケーションサーバーのみ。 なぜかというと、コンテナ間の連携をちゃんとやる時間が無かったから・・。
というわけで、コンテナ間の連携、JenkinsからのWildFlyへのリモートデプロイをできるようにするのが、本エントリの目標です。
Dockerコンテナ間連携
まだしばらく同一サーバー内でのコンテナ間連携で行けそうなので、--link
を使います。
https://docs.docker.com/docker/userguide/dockerlinks/#communication-across-links
今回の場合はJenkinsサーバーコンテナから、アプリケーションサーバーコンテナへリンクします。
アプリケーションサーバーの起動
--name
オプションで、apppot_runtime1.7
という名前でコンテナを起動させています。
docker run -it --expose 9181 -p 9181:8080 -p 9991:9990 --name apppot_runtime1.7 rsogo/wildfly8:v1 /bin/bash
Jenkinsサーバーコンテナの起動
--link
オプションで、apppot_runtime1.7
という名前のコンテナをリンクさせています。
docker run -it --expose 8081 -p 8081:8080 --name jenkins --link apppot_runtime1.7:apppot_runtime1.7 rsogo/jenkins:v5 /bin/bash
コンテナIDでもリンクで指定することはできますが、コンテナIDはコンテナの起動の度に変わります。 上のような起動スクリプトはシェルとして用意しておきたいと思いますので、コンテナIDより、コンテナ名を定義しておいた方が便利です。
Jenkinsサーバーコンテナでのhostsファイル、環境変数の確認
apppot_runtime1.7
がhostsファイルに追加されていることが分かります。
# cat /etc/hosts 172.17.0.71 cfc8c054ccf8 127.0.0.1 localhost 172.17.0.69 apppot_runtime1.7 9b5ee14ff469
env
コマンドを実行した結果、環境変数にアプリケーションサーバーコンテナが公開しているポートごとに次のような環境変数が定義されています。
APPPOT_RUNTIME1.7_PORT_8080_TCP_ADDR=172.17.0.69 APPPOT_RUNTIME1.7_PORT=tcp://172.17.0.69:22 APPPOT_RUNTIME1.7_PORT_22_TCP_PORT=22 APPPOT_RUNTIME1.7_PORT_22_TCP_ADDR=172.17.0.69 APPPOT_RUNTIME1.7_PORT_22_TCP=tcp://172.17.0.69:22 APPPOT_RUNTIME1.7_PORT_9181_TCP_PORT=9181 APPPOT_RUNTIME1.7_PORT_22_TCP_PROTO=tcp APPPOT_RUNTIME1.7_PORT_8080_TCP_PORT=8080 APPPOT_RUNTIME1.7_PORT_9990_TCP=tcp://172.17.0.69:9990 APPPOT_RUNTIME1.7_PORT_9080_TCP_PORT=9080 APPPOT_RUNTIME1.7_PORT_9181_TCP_PROTO=tcp APPPOT_RUNTIME1.7_PORT_8080_TCP=tcp://172.17.0.69:8080 APPPOT_RUNTIME1.7_PORT_8080_TCP_PROTO=tcp APPPOT_RUNTIME1.7_PORT_9080_TCP_PROTO=tcp APPPOT_RUNTIME1.7_PORT_9990_TCP_ADDR=172.17.0.69 APPPOT_RUNTIME1.7_PORT_9080_TCP_ADDR=172.17.0.69
この状態で、Jenkinsサーバーコンテナから以下のコマンドを実行することで、JenkinsサーバーからWildFlyのポートにアクセスできることを確認できます。
# curl http://apppot_runtime1.7:8080 <!-- ~ JBoss, Home of Professional Open Source. ~ Copyright (c) 2011, Red Hat, Inc., and individual contributors 略
次は、JenkinsサーバーからWildFlyへリモートデプロイします。