normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

How to update your Java application in ACS Kubernetes

This post is continuation of . Please read the post before this one if you haven't read it. I will show you how to update your Java application in ACS kubernetes in this post.

Update your Java application - Run this section at your Windows Docker Client

At first, update your Java application. Modify your "index.jsp" file like below.

<html>
 <head>
  <title>Docker deployed apps !!update!!</title>
 </head>
 <body>
  <h2>Hello World! on Docker !!update!!</h2>
 </body>
</html>

And run "mvn package" command in the Java project folder. After create new war file in "helloworld/target/helloworld.war", create new Docker image and launch the application by running below commands.

helloworld>docker build --no-chache -t normalian/wildfly-helloworld .

helloworld>docker images
REPOSITORY                                                  TAG                 IMAGE ID            CREATED             SIZE
normalian/wildfly-helloworld                                latest              xxxx2536f9e2        11 seconds ago      584MB
xxxxxxxxxxxxxxxxx.azurecr.io/normalian/wildfly-helloworld   latest              xxxx171bcbcf        40 minutes ago      584MB
jboss/wildfly                                               latest              xxxx152f84f9        5 days ago          584MB

helloworld>docker run -it --rm -p 8080:8080 normalian/wildfly-helloworld

After above, access http://localhost:8080/helloworld. Stop the application if you can check your update.

Push your Docker image into your private repository on Azure by running below commands.

helloworld>docker tag normalian/wildfly-helloworld xxxxxxxxxxxxxxxxx.azurecr.io/normalian/wildfly-helloworld

helloworld>docker push xxxxxxxxxxxxxxxxx.azurecr.io/normalian/wildfly-helloworld
The push refers to a repository [xxxxxxxxxxxxxxxxx.azurecr.io/normalian/wildfly-helloworld]
xxxx02afd48c: Pushed
xxxx5bc19b9a: Pushed
xxxx11518954: Layer already exists
xxxx13dfbb96: Layer already exists
xxxx519728f4: Layer already exists
xxxx7c284ded: Layer already exists
xxxx8d9413e4: Layer already exists
latest: digest: sha256:xxxxxxxxxxxxxxxxx1522ee990cd74155116034b15ab51198ecc9a7e246a926 size: 1789

Update your Java application - Run this section at Kubernetes master node

Connect Kubernetes master node by SSH(e.x, Bash on Ubuntu on Windows). Run below commands.

azureuser@k8s-master-3AEAFCA1-0:~$ kubectl set image deployment my-java-app01 my-java-app01=xxxxxxxxxxxxxxxxx.azurecr.io/normalian/wildfly-helloworld
deployment "my-java-app01" image updated

azureuser@k8s-master-3AEAFCA1-0:~$ kubectl get pod
NAME                             READY     STATUS              RESTARTS   AGE
my-java-app01-2735613267-h0gsp   0/1       ContainerCreating   0          5s
my-java-app01-979249178-1k5c9    1/1       Running             0          35m

azureuser@k8s-master-3AEAFCA1-0:~$ kubectl get services
NAME            CLUSTER-IP    EXTERNAL-IP    PORT(S)          AGE
kubernetes      10.0.0.1      <none>         443/TCP          3d
my-java-app01   10.0.174.35   23.99.81.xxx   8080:32298/TCP   1h

After above, access http://23.99.81.xxx:8080/helloworld via browser. You can check your updated Java application.

Please note "kubectl set image deployment my-java-app01 my-java-app01=xxxxxxxxxxxxxxxxx.azurecr.io/normalian/wildfly-helloworld:latest" won't work when you use "latest" tag for your Docker images.

What should you do when you got "Error response from daemon ... [::1]:53: read udp [::1]:33230->[::1]:53: read: connection refused"?

When I tried to run "docker login" command, I got below error.

Error response from daemon: Get https://xxxxxxxx.azurecr.io/v2/: dial tcp: lookup xxxxxxxx.azurecr.io on [::1]:53: read udp [::1]:33230->[::1]:53: read: connection refused

I'm not sure what's this, but I found this article.
github.com

Following the article, I re-install Docker Windows. I finally succeed to login remote Docker repository.

C:\Users\normalian>docker login xxxxxxxx.azurecr.io
Username (xxxxxxxx):
Password:
Login Succeeded

ロサンゼルス生活日誌 ~その2 ロサンゼルス国際空港はどんなところ?~

(現地時間的に)おはようございます。今回は日本の方が最初に到着するであろうロサンゼルス国際空港(通称 LAX)について紹介したいと思います。当然ですが、アメリカ合衆国における西の玄関ともいわれる空港であるので非常に大きいです。
f:id:waritohutsu:20170710023658p:plain

乗り換えて国内移動をさらに行う場合はさておき、日本の方なら国際線で来ると思いますので、原則以下の Tom Bradley International Terminal という場所に到着するはずです。
f:id:waritohutsu:20170710023732p:plain

今回はこちらに到着後、何をどうしたものか的なところを紹介したいと思います。

空港内での WiFi はどうしよう?

無料の WiFi が提供されています。以下の投稿でも記載がありますが「_LAX Free WiFi」という SSID が利用可能です。


こちらの英語記事にステップが記載されていますが、SSID を指定して接続後、ブラウザで「広告を見る代わりに45分接続するよ」という旨の英語ボタンを押せば利用可能になります。
http://yourhelloworld.com/wifi-details-for-los-angeles-international-airport-lax/

45分以上の利用は再度ブラウザ経由でログインする必要がありますが、何回ログインするかの制限はないので、相手が待ち合わせに遅れた場合等で連絡する際に困ることはないと思います。

出口周辺での待ち合わせスポットは?

ロサンゼルスに到着後、原則 1F に到着します。入国審査・荷物受け取り後は以下の場所に到着するので、ストリートビュー等で風景を確認してみるとわかりやすいです。
f:id:waritohutsu:20170710023757p:plain

ストリートビューの風景は以下になりますが、出口近辺に Coffee Beans があるので時間があるなら一息ついてみるのも良いと思います。クレジットカード(日本のものでもOK)を持っていれば一杯数ドルでコーヒーが飲めます。
更に、この場所でも「_LAX Free WiFi」は使えるはずなので、こちらを待ち合わせ場所にするのも悪くないと思います。
f:id:waritohutsu:20170710023817p:plain

Uber に乗る場合はどうしよう?

慣れない場所に来た以上、いきなりレンタカーよりも Uber を使う方が多いと思います。この際に要注意なのが、LAX 周辺では任意の場所に Uber 配車を指定することが原則できません(おそらく混雑しすぎているのが原因だと思いますが、強引にしても Uber のあんちゃんがキャンセルしてくること多しです…)。こちらは以下の Uber 記事にも載っています。
https://www.uber.com/drive/los-angeles/airports/los-angeles-international-airport/

上記の英語記事のうち「Step by step pickups at LAX」の箇所に画像がありますが、以下の B と C どちらかの箇所に配車をお願いするケースが多いと思います。
f:id:waritohutsu:20170710023847p:plain

配車を実施後に注意が「到着は1Fだが、Uber が配車されるのは2F」という点です。移動時には気を付けてください。

レンタカーをいきなり利用する場合は?

私は AVIS レンタカーしか利用したことがありませんが、空港から離れた場所にあります。そのため、バスに乗って移動するので注意してください。5分~10分毎くらいでバスが周遊しているので、ちょっと待てばすぐきます。空港入り口を出て数百メートル程度の距離にあります。

ロサンゼルス生活日誌 ~その1 ロサンゼルスはどんな町?~

こんにちは。先月からロサンゼルス勤務となったので、色々と出来事なり今後米国(特にロサンゼルス)に来る方へ参考になる情報を色々と書いていきたいと思います。2回の出張を経ておおよそひと月の滞在になるものの、分からないがゆえに困ったことや戸惑ったことも多く、多くの日本人の方も同様に困るものが多いなと思ったといいます。ロサンゼルスに情報は偏りますが、せっかくなのでこちらでノウハウをまとめていきます。今後、米国移住を考えている方に少しでも役にたてば幸いです。

ロサンゼルスってどこにあるの?

米国の南西側にあるカリフォルニア州に位置しますが、Wikipedia の項目 によればニューヨークに次ぐ全米有数の世界都市とのこと。
以下は Bing Maps のスクリーンショットですが、メキシコの国境にかなり近いので都市部にはメキシカンの方々が多いです。メキシカンの方も多いですが、白人の方、黒人の方はもちろんアジア人も多いので、ふらふら歩いてると色んな方を見かけます(ロサンゼルスは地区により人種比率が大きく変動します)。
f:id:waritohutsu:20170709112143p:plain
地図上から見るとサンフランシスコが近く見えますが、車で移動すると5時間位はかかるとのことなので気軽な旅はできません(汗

ロサンゼルスの交通事情

ロサンゼルスにも電車やバスはありますが、車を購入できる程度の所得がある人は車を購入して車で移動する文化です。そのため、以下の様に日中の道路は常に込みまくりです。

上記の投稿で記載がある「フリーウェイ」は日本でいう「首都高速」のようなものですが、首都高速と違って誰でも無料で利用できるので常に混んでおりいてこんな状況です。
f:id:waritohutsu:20170709113259p:plain
ロサンゼルス在住歴が長い知人は出勤時間をずらしたりフリーウェイを利用しない方法で渋滞を回避していますが、同僚曰くで「渋滞がなければ1時間の道が3時間かかったよ」の発言もあったりするのでかなり深刻な社会問題の様です。

ロサンゼルスの天気

常に晴れており天気は最高です。体感ベースでは「8割快晴、2割が晴れ」位の割合で、ひと月くらいは滞在していますが一度も雨が降ったことがありません。
f:id:waritohutsu:20170415133009j:plain
日差しが強力なので女性に限らずUVカットは必須だと思われますが、かなり乾燥しているので蒸し暑さがなく、日陰に入るとかなり快適です。もっとも生活する上では乾燥しすぎるきらいはあるので、快適に過ごすためには加湿器はかなり必須だと思います。

まずはで軽く解説させて頂きましたが、引き続きいろんな情報を載せていきたいと思います。

How to deploy your Java applications into Azure Container Service

As you know, Azure Container Service(ACS) has some orchestrators such like DC/OS, Swarm and Kubernetes. In this post, you can get below knowledge.

What's requirement to use ACS for Java

In this post, I use my Windows machine for Docker client. Please prepare below environment at first to deploy your Java applications into ACS Kubernetes.

How to make Java application Docker images

Run below maven command in general command prompt. You can find your Java web application in your current directory. Please change "groupId" and "artifactId" for your environment.

mvn archetype:generate -DgroupId=com.mydomain -DartifactId=helloworld -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

Please edit helloworld\src\main\webapp\index.jsp like below if you need.

<html>
 <head>
  <title>Docker deployed apps</title>
 </head>
 <body>
  <h2>Hello World! on Docker</h2>
 </body>
</html>

Create Dockerfile for your application in your Java project folder like below.

FROM jboss/wildfly
MAINTAINER normalian

ADD ./target/helloworld.war /opt/jboss/wildfly/standalone/deployments

EXPOSE 8080

This Dockerfile pull public "jboss/wildfly" Docker image, deploy your application into WildFly and expose 8080 port for web accesses.

Create a Docker image with your application to run below command in your Java project folder.

helloworld>docker build -t normalian/wildfly-helloworld .
Sending build context to Docker daemon  35.33kB
Step 1/4 : FROM jboss/wildfly
 ---> ec96c1eb76d4
Step 2/4 : MAINTAINER normalian
 ---> Using cache
 ---> f445b07e38f8
Step 3/4 : ADD ./target/helloworld.war /opt/jboss/wildfly/standalone/deployments
 ---> Using cache
 ---> 92fd373f0f55
Step 4/4 : EXPOSE 8080
 ---> Using cache
 ---> 13a52eeb004a
Successfully built 13a52eeb004a
Successfully tagged normalian/helloworld-test:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

You will find a warning, but you can ignore the warning in this post. Please consider it depending on your environment. After that you can check your docker image and run your application with the image.

helloworld>docker images
REPOSITORY                                                  TAG                 IMAGE ID            CREATED             SIZE
normalian/wildfly-helloworld                                latest              9c25b0840c8c        9 minutes ago       584MB

helloworld>docker run -it --rm -p 8080:8080 normalian/wildfly-helloworld

Please access http://localhost:8080/helloworld/index.jsp with your browser. You can watch your jsp file of your application. After that, please stop your container, and the container will remove caused by "--rm" option.

How to push your Docker images into "Container registries" in Microsoft Azure

Access https://portal.azure.com/ and create your "Container registries". Please refer this article https://docs.microsoft.com/en-us/azure/container-service/container-service-tutorial-kubernetes-prepare-acr if you need. After creating "Container registries", you can get "Registry name", "Login server" and "password" via the portal. Please refer below image.
f:id:waritohutsu:20170705120644p:plain

Run below command to push your docker image into your "Container registries" in Microsoft Azure.

helloworld> docker login --username=<username> --password=<password> xxxxxxxx.azurecr.io
helloworld> docker tag normalian/wildfly-helloworld xxxxxxxx.azurecr.io/normalian/wildfly-helloworld
helloworld> docker push xxxxxxxx.azurecr.io/normalian/wildfly-helloworld

After that, you can watch your image in your "Container registries" like below.
f:id:waritohutsu:20170705120956p:plain

Please read this section at first if you haven't setup ssh in your client machine. Launch "Bash on Ubuntu on Windows" in your client machine, and run below commands.

normalian@k8s-master-2E00DAB3-0:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/normalian/.ssh/id_rsa):
Created directory '/home/normalian/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/normalian/.ssh/id_rsa.
Your public key has been saved in /home/normalian/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX normalian@k8s-master-2E00DAB3-0
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|      o          |
|   . o o      . .|
|  + B *  .   . = |
|E+ X X +S o . + o|
|o O =.=  . = + . |
| +...o... o +    |
|oo ... ...       |
|O .oo...         |
+----[SHA256]-----+
normalian@k8s-master-2E00DAB3-0:~$

Refer this article https://github.com/yoshioterada/DEIS-k8s-ACS/blob/master/KubernetesOnAzureContainerService.md, and follow steps "until Login to the master node of ACS".

How to deploy and run your Java applications on ACS

Make a yaml file to define your application in master node of Kubernetes, and run below commands to publish your docker image.

normalian@k8s-master-2E00DAB3-0:~$ vi java-app-deployment.yaml
normalian@k8s-master-2E00DAB3-0:~$ cat java-app-deployment.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: my-java-app01
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: my-java-app01
    spec:
      containers:
      - name: my-java-app01
        image: zzzzzzzzzzzzzz.azurecr.io/normalian/wildfly-helloworld:latest
        ports:
        - containerPort: 8080
          name: wildfly

normalian@k8s-master-2E00DAB3-0:~$ kubectl create -f java-app-deployment.yaml
normalian@k8s-master-2E00DAB3-0:~$ kubectl get deployments
NAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
my-java-app01   1         1         1            1           4h

normalian@k8s-master-2E00DAB3-0:~$ kubectl expose deployment my-java-app01 --type=LoadBalancer

You can't access via internet without "kubectl expose deployment my-java-app01 --type=LoadBalancer", because Kubernetes deploy docker images into its own network. After this, run below commands to get IP to access from internet.

normalian@k8s-master-2E00DAB3-0:~$ kubectl get service
NAME            CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
kubernetes      10.0.0.1     <none>        443/TCP          4h
my-java-app01   10.0.3.145   <pending>     8080:30226/TCP   2m
normalian@k8s-master-2E00DAB3-0:~$ kubectl get service
NAME            CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
kubernetes      10.0.0.1     <none>        443/TCP          4h
my-java-app01   10.0.3.145   13.91.1.xx    8080:30226/TCP   3m

Input "http://13.91.1.xx:8080/helloworld" in your browser, and you can access your Java application.

Cognitive Services の Emotion API を利用する

AI 熱が過熱している昨今、Microsoft は Cognitive Services の各 API リリース&ブラッシュアップし続けている。REST API を直接利用するサンプルは多いが、SDK を利用したサンプルが以外に少ないので自身の備忘録として記載する。プログラムの動作までには以下のステップが必要だ。

  • Microsoft Azure の管理ポータルで Cognitive Services のアカウントを作成し、Subscription Key を取得する
  • Visual Studio で新規プロジェクトを作成し、NuGet で Microsoft.ProjectOxford.Emotion を取得する
  • ソースコードの記載、実行

まずは Microsoft Azure の管理ポータルにログインし、以下の画面の様な Cognitive Services の Emotion API アカウントを作成し、KEY1 を取得する(KEY2 でも良い)。
f:id:waritohutsu:20170221125557p:plain

次に Visual Studio を起動し、「NuGet パッケージ管理」から以下の画面に従い Microsoft.ProjectOxford.Emotion をインストールする。
f:id:waritohutsu:20170221125602p:plain

最後に、以下のソースコードを記載してアプリケーションを実行する。

using Microsoft.ProjectOxford.Emotion;
using System;
using System.Linq;
using System.IO;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new EmotionServiceClient("your subscription key on Microsoft Azure portal");
            string path = @"D:\temp\myimage01.png";
            MakeRequest(client, path).Wait();
            Console.WriteLine("ENTER to end this app....");
            Console.ReadLine();
        }

        static async Task MakeRequest(EmotionServiceClient client, string path)
        {
            using (var fileStream = new FileStream(path, FileMode.Open))
            {
                // 認識した顔の数だけ実行
                var emotions = await client.RecognizeAsync(fileStream);
                foreach (var emotion in emotions)
                {
                    Console.WriteLine("Anger = {0}, Contempt = {1}, Disgust = {2}, Fear = {3}, Happiness = {4}, Neutral = {5}, Sadness = {6}, Surprise = {7}",
                        emotion.Scores.Anger,
                        emotion.Scores.Contempt,
                        emotion.Scores.Disgust,
                        emotion.Scores.Fear,
                        emotion.Scores.Happiness,
                        emotion.Scores.Neutral,
                        emotion.Scores.Sadness,
                        emotion.Scores.Surprise);
                }
            }
        }
    }
}

以下の様に実行結果が表示される。

Anger = 1.391707E-05, Contempt = 0.004622553, Disgust = 1.419089E-05, Fear = 4.515473E-06, Happiness = 0.8965916, Neutral = 0.09813519, Sadness = 4.940341E-05, Surprise = 0.0005686138
ENTER to end this app....

顔が検出されない場合、上記の foreach 文に入らない点に留意してほしい。

ARM 版の Application Gateway を PowerShell で作成する

今回はコマンドラインにて Application Gateway を作成する。Application Gateway をご存じでない方のために簡単に捕捉すると「機能が豊富なロードバランサ( Azure ロードバランサ比)」だ。よく使いたいといわれる Application Gateway の機能は以下だ。

  • cookie ベースでの振り分け
  • パスベースでのアクセス振り分け( デフォルトは サーバ A、/admin/* はサーバ B 等)
  • SSL オフロード

一方でApplication Gateway は有料であり、中規模以上で2インスタンス以上でないと SLA が保証されない点に注意してほしい。以下は Application Gateway の価格 の抜粋だ。

Microsoft は、複数の中規模またはより大規模なインスタンスを持つ各 Application Gateway Service に対し、
99.95% 以上の可用性を保証します。インスタンスが 1 つのみ、あるいは小規模なインスタンスしか含まれない
 Application Gateway Services に関しては SLA は提供していません。SLA の詳細については、SLA のページを
ご覧ください。

パスベースのルールを持つ Application Gateway を作成する PowerShell スクリプト

Application Gateway は管理ポータルからでも作成できるが、ルール名等々を柔軟に設定するには PowerShell が有効なので、以下を備忘録として張り付けておく。以下が前提なことに注意してほしい。

  • リソースグループ my-demo-rg が作成済み
  • 仮想ネットワーク my-demo-vnet が作成済みであり、waf-subnet が作成済み
  • Application Gateway が配置されるサブネットと通信できる場所に 10.0.1.10 アドレスの WEB サーバが配置済み
  • Application Gateway が配置されるサブネットと通信できる場所に 10.0.1.20 アドレスの WEB サーバが配置済み
# まずはログイン
Get-AzureRmSubscription

# 利用サブスクリプションを選択
Select-AzureRmSubscription -SubscriptionId "your subscription id"

# 配置先のリソースグループ、仮想ネットワーク、サブネット、リージョンを指定
$rgName = "my-demo-rg"
$vnetName = "my-demo-vnet"
$subnetName = "waf-subnet"
$location = "japanwest"
$publicIPName = "APPGW-Public-IP"
$wafName = "my-gateway"

$vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
$subnet = $vnet.Subnets[0]
$publicip = New-AzureRmPublicIpAddress -ResourceGroupName $rgName -name $publicIPName -location $location -AllocationMethod Dynamic
$gipconfig = New-AzureRmApplicationGatewayIPConfiguration -Name $wafName -Subnet $subnet

# 振り分け先のサーバを指定、複数指定する場合は , でつなげる
$defaultPool = New-AzureRmApplicationGatewayBackendAddressPool -Name defaultPool -BackendIPAddresses 10.0.1.10 #1d34.170.185.46, 134.170.188.221,134.170.185.50
$adminPool = New-AzureRmApplicationGatewayBackendAddressPool -Name adminPool -BackendIPAddresses 10.0.1.20 #1d34.170.185.46, 134.170.188.221,134.170.185.50

# 80 番ポートを指定し、cookie ベースの振り分けを有効化
$poolSetting = New-AzureRmApplicationGatewayBackendHttpSettings -Name appGatewayBackendHttpSettings -Port 80 -Protocol Http -CookieBasedAffinity Enabled
$fp = New-AzureRmApplicationGatewayFrontendPort -Name frontendport01  -Port 80
$fipconfig = New-AzureRmApplicationGatewayFrontendIPConfig -Name appGatewayFrontendIP -PublicIPAddress $publicip

# デフォルトは 10.0.1.10、/admin/* は 10.0.1.20 の振り分け指定
$listener = New-AzureRmApplicationGatewayHttpListener -Name appGatewayHttpListener -Protocol Http -FrontendIPConfiguration $fipconfig -FrontendPort $fp
$adminPathRule = New-AzureRmApplicationGatewayPathRuleConfig -Name "adminPathrule" -Paths "/admin/*" -BackendAddressPool $adminPool -BackendHttpSettings $poolSetting
$urlPathMap = New-AzureRmApplicationGatewayUrlPathMapConfig -Name "urlpathmap" -PathRules $adminPathRule -DefaultBackendAddressPool $defaultPool -DefaultBackendHttpSettings $poolSetting
$adminRule = New-AzureRmApplicationGatewayRequestRoutingRule -Name "adminRule" -RuleType PathBasedRouting -HttpListener $listener -UrlPathMap $urlPathMap

# SLA が担保される SKU を指定
$sku = New-AzureRmApplicationGatewaySku -Name "Standard_Medium" -Tier Standard -Capacity 2
$appgw = New-AzureRmApplicationGateway -Name appgwtest -ResourceGroupName $rgName -Location $location -BackendAddressPools $defaultPool, $adminPool -BackendHttpSettingsCollection $poolSetting -FrontendIpConfigurations $fipconfig -GatewayIpConfigurations $gipconfig -FrontendPorts $fp -HttpListeners $listener -UrlPathMaps $urlPathMap -RequestRoutingRules $adminRule -Sku $sku -Debug

上記を実行すれば ARM 版の Application Gateway が作成されるはずだ。

参考