まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

マンホール蓋の位置情報付きポータルサイトであるマンホールマップは、Twitter の OAuth ログインによってユーザー認証を行い、ログイン後にマンホール画像を投稿できる機能が有効になります。が、ログインしなくても投稿済み情報を参照できるようになっています。


この参照できる情報には投稿されたマンホール画像やその位置情報(地図)だけでなく、投稿者の情報も含まれています。投稿者の名前だけでなく、Twitter アイコン(プロフィール画像)も表示されます:
2020060401



【起こった問題】
正確にはどのタイミングからだったのかわからないのですが、先日からマンホールマップにこの Twitter アイコンが表示されなくなる、という現象が起こっていました。


マンホールマップ側に変更がない状況で表示されていたものが表示されなくなった。ということは Twitter で何かあった?一時的な障害であることを祈っていたのですが1日経過しても状況は変わりませんでした。もしかして Twitter API が変更になったのかなあ、、という可能性も考えたのですが、明確なアナウンス類を見つけることができませんでした。ただ 2019 年に発表されたこの変更予告を見逃していて、もしかしたら今年の5月末くらいに実装からも外れて・・・みたいな感じで関係あったのかなあ(未確認)・・・という感じ:
https://twittercommunity.com/t/upcoming-changes-to-user-object-and-get-users-suggestions-endpoints/124732/2

2020060404



これまでのマンホールマップでの Twitter アイコン取得方法と同じ方法(後述)を解説していたこちらのページの中でも画像が表示されているべき(と思われる)箇所の画像が表示されていません。つまりマンホールマップにだけ発生している現象というわけではなく、このページでも自分と同じ現象が起こっているように感じました:
Twitter APIで取得したプロフィール画像のサイズを変更する


(↓この部分、本来は画像が表示されている??)
2020060403



ともあれ詳しい状況はわからないままですが、表示されなくなった Twitter アイコンを復活させるべく行った緊急対応の顛末を記録しておきます。結論として現時点(2020/06/04)で応急処置的にアイコンが表示されるよう復活しています。



【これまでの Twitter アイコン取得方法】
もう公式ドキュメントには記載されておらず、どこにこの方法について言及したドキュメントがあったのかも覚えてないのですが、これまでは以下のように HTTP API を2回使って Twitter アイコン画像の URL を取得していました:

(1)GET https://twitter.com/screen_name/profile_image にアクセス(screen_name 部はアイコンを表示したい人の Twitter アカウントの表示名※)
(2)(1)の結果得られる JSON オブジェクトから request.path の値を取り出す( "/12345/67890.jpg" みたいな値が取り出される)。
(3)HTML で <img src="https://pbs.twitter.com(request.path の値)"/> などのようにするとアイコン画像が表示できる


※Twitter アカウントの表示名とは、アカウントのページを開いた時のこの部分(赤枠)のことです:
2020060402



これまでのマンホールマップではこの方法で投稿者の Twitter アイコン画像を表示していました。上述の「ここでも自分と同じ現象が起こっている・・・」と書いたリンク先でも同じ手法が紹介されていますが、マンホールマップ同様に表示できなくなっているようでした。

調査した結果を記載しておくと、上述の方法で(1)と(2)は結果を得ることができているのですが、(3)で指定する URL にブラウザでアクセスすると 404 エラー(存在しない URL)となりました:
2020060402


ただ、では(1)と(2)が成功しているのかというと、どうも怪しいと思っています。(1)を実行した結果得られる(2)の値は以前は実行するまで推測できないパス名だったのですが、いま実行すると '/screen_name/profile_image' という結果となりました(つまり(1)を実行した時のパスがそのまま返ってくる)。この時点で以前のアイコンが正しく表示出来ていた頃とは結果が異なっているので、もしかすると(1)が以前のように動かなくなっていることが、アイコンが表示されない直接の原因なのかもしれない、、と推測しています。


いずれにしても、この API はもう使えなくなっちゃったのかな・・・ 結論として後述の応急手当的な対応はできたのですが、正直、今でもこの方法に戻せるなら戻して使いたいと思っています。理由も含めて後述します。


【現時点での正攻法(Twitter API を使う方法)】
上で紹介した方法以外に、(ちゃんと)Twitter API ドキュメントで紹介されている方法を使ってアイコン画像を取得する(正攻法的な)方法もあります。逆にいうと上述の方法は現在の Twitter API ドキュメントを探しても見つからない、ある種の「裏ワザ」的な方法だったりします(苦笑)。

正攻法というのは、具体的には GET /users/show API を使う方法です:
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show

2020060403


この API を実行する際のパラメータでアイコンを取得するユーザーの screen_name を指定します。すると指定したユーザーの情報を得ることができ、その中にはプロフィール画像(アイコン)の URL が含まれているので、その値を使うことでアイコン画像を表示することができる、というものです。


【正攻法(Twitter API を使う方法)では駄目な理由】
しかしこの方法はマンホールマップでの実装には向かない大きな理由があります。それはこの API はアクセストークンを使って実行する必要があるのですが、ユーザーがログインしていないとアクセストークンが取得できないのです。つまりユーザーがログインする前や、そもそもログインしないユーザーからするとアクセストークンを取得するタイミングがないので、この API を使うことが出来ず、アイコンを表示できないのでした。

マンホールマップは上述のようにログインしなくても参照できることを謳ってきていた背景もあり、Twitter 側に仕様変更があったとしても、急にマンホールマップにもログインを必須にすることに抵抗を感じてしまいました。。 そんな背景もあり、この正攻法での方法は採用していません。


【応急処置による現在の Twitter アイコン取得方法】
で、結論としてはこの方法を採用しているのですが、では改めてユーザーのログインなしにどうやって Twitter アイコンを取得しているか、を紹介します。あくまで応急手当的な内容であり、実行効率はよくない(のでできれば早く修正したい)ことを自覚している方法であることをご了承ください。

実現方法を簡単に言うと「Twitter にログイン済みの別プロセスを使って API を実行する」方法です。以下でもう少し詳しく紹介しますが、その前に twurl というコマンドラインツールを紹介します。
https://github.com/twitter/twurl

2020060404



twurl (読み方わからず・・)は Twitter 謹製の Twitter API 専用 curl といった位置づけのオープンソース製品です。各種 Twitter API を必要であればパラメータを付けてコマンドラインから実行し、その結果を標準出力に取り出すことができます。このツールも実行前に OAuth によるログインが必要ですが、ログインを1度実行しておけば、そのあとの API 実行は続けて行うことができます。標準の curl でも Twitter API を実行することは可能ですが、パラメータとして与える署名の計算が毎回面倒だったりするわけです。一方 twurl を使うとそのあたりは裏でバッチリやってくれるらしく、必要最小限のパラメータだけを渡して実行することができる、というものです。

例えば上述した正攻法による API で紹介した GET /users/show API を使ってユーザー情報を取得する場合であれば、セットアップ後にこういったコマンドを実行します(curl と同様ですが、"-X GET" は既定値なので省略可能です):
$ twurl -X GET /1.1/users/show.json?screen_name=dotnsf

これで screen_name が dotnsf(僕のアカウントです)であるユーザーの情報を取得することができます。結果は JSON で得ることができますが、この中の "profile_image_url_https" キーの値がそのユーザーの Twitter アイコン画像を表示するための URL 、ということになります:
$ twurl -X GET /1.1/users/show.json?screen_name=dotnsf
{
  "id": XXXX....,
  "id_str": "XXXX....",
    :
  "profile_image_url_https": "https://pbs.twitter.com/AAAAAAAA/BBBBB.jpg",
    :
}

この値が目的の URL 文字列です。したがって twurl コマンドを使うと目的の文字列を取得することができることがわかりました。


で、今回の API 代替方法というのは、この twurl を外部プロセスで実行して対象 Twitter ユーザーのアイコン画像の URL を取り出し、この URL を使ってアイコンを表示する、という方法です。外部プロセスを使うのがちとダサいのですが、一方でこの方法なら Node.js 実行前に twurl のセットアップを済ませておけば、Twitter API 実行のためのウェブアプリケーション側でのログインは不要となるので、参照目的のユーザーであっても(ログインしなくても)アイコンが表示される、ということが実現できるようになります。

マンホールマップのソースコードは現時点においては非公開ですが、この該当部分だけを別アプリケーションにして github で公開しています:
https://github.com/dotnsf/twurl


このアプリケーションは上述の twurl を別プロセスで動かして目的の URL を取得する、という内容を Node.js で実現するサンプルです。おそらく他のプログラミング言語であっても(外部コマンドを実行して、その結果を取得する機能があれば)実現できると思っています。

サンプルアプリの使い方ですが、まずアプリケーションを実行する前に twurl をセットアップする必要があります。詳しくは twurl の github 内にも記載されていますが、一応こちらでも(日本語で)以下に紹介します。

まず twurl は Ruby Gem を使ってインストールします。そのため Ruby(& Gem) 環境が必要です。Ruby がインストールされていない環境の場合はインストールしておきましょう。 Ubuntu 環境下であればこんな感じで:
$ sudo apt-get install ruby

Ruby Gem が導入されている環境で、以下のコマンドを実行すると twurl が導入されます:
$ sudo gem install twurl

これで(Ubuntu であれば /usr/local/bin/twurl として)twurl がインストールされました。次に twurl のセットアップが必要です。Twitter Developers にアプリを登録し、Consumer Key と Consumer Secret を取得した上で以下のコマンドを実行します:
$ twurl authorize --consumer-key (Consumer Key) --consumer-secret (Consumer Secret)

このコマンドを実行すると「この URL を開け」という指示が表示されます。その URL をブラウザで開くと認証用の文字列が表示され、それと同じ内容を実行中の twurl コマンドの入力待ちプロンプトに打ち込んで Enter キーを押します。正しい文字列が指定されていれば認証が完了し、twurl コマンドが使えるようになります。試しに上述の GET /users/show コマンドを実行するなどしてみてください:
$ twurl /users/show?screen_name=dotnsf
(screen_name が dotnsf であるユーザーのプロフィール情報が表示されます)

これで twurl を実行する準備が整いました。あとは Node.js のアプリケーションからこのコマンドを外部呼び出しで実行し、その結果を取得・解析してプロフィール画像の URL へリダイレクトさせることで目的の機能が実現できそうです。


twurl のセットアップができた所で、改めてこのサンプルアプリケーションを動かしてみます:
https://github.com/dotnsf/twurl


このサンプルアプリケーションの app.js ファイルは以下のようになっています:
//.  app.js
var express = require( 'express' ),
    app = express();
var { execSync } = require( 'child_process' );
var settings = require( './settings' );

app.get( '/', function( req, res ){
  var screen_name = req.query.screen_name;
  if( screen_name ){
    try{
      var stdout = execSync( settings.twurl_command + ' /1.1/users/show.json?screen_name=' + screen_name );
      var obj = JSON.parse( stdout.toString() );
      var profile_image_url_https = obj.profile_image_url_https;
      res.redirect( profile_image_url_https );
    }catch( e ){
      return res.status( 403 ).send( { status: false, error: e } );
    }
  }else{
    return res.status( 403 ).send( { status: false, error: 'No screen_name provided.' } );
  }
});

var port = process.env.PORT || 8080;
app.listen( port );
console.log( "server starting on " + port + " ..." );

そして別ファイルである settings.js は以下のような設定にしています:
//. settings.js
exports.twurl_command = '/usr/local/bin/twurl';


簡単に解説しておくと、GET / をハンドルする API だけが定義されています。そしてこの API では screen_name というパラメータを受け取って、
$ /usr/local/bin/twurl /users/show.json?screen_name=(パラメータの値)

を同期的に実行し(twurl のパスは settings.js 内に記載)、実行結果が stdout 変数に格納されます。そして格納された結果を JSON パースした上で "profile_image_url_https" の値を取り出して、その URL にリダイレクトする、という処理を行っています。 これによってパラメータで指定した screen_name を持つ Twitter ユーザーのプロフィールアイコン画像を表示する、という処理を実現しています。

実際にサンプルアプリケーションを動かして、ブラウザで http://localhost:8080/?screen_name=dotnsf を実行した結果がこちらです:
2020060401


http://localhost:8080/?screen_name=dotnsf にアクセスすると、twurl の実行結果に含まれる URL に転送され、screen_name パラメータで指定した Twitter ユーザー(この場合であれば @dotnsf)のプロフィールアイコン画像が表示できました。twurl のセットアップ時に consumer_key と consumer_secret を指定してはいますが、そのあとのアプリケーション実行時には Twitter の OAuth ログインなしに Twitter API を実行して結果を取得することができています。

実用上においては、Twitter アイコンを表示するたびに twurl を使うこの一連の処理を実行するのは重すぎるので、一度取得した結果をキャッシュしておくなどの対処が必要になると思っています。ただこのやりかたで一応、挙動としては最低限の目的を達成することができました。

というわけで、無事にマンホールマップで投稿者の Twitter アイコンは応急処置的に復活できています:
2020060405


このフローは以前に少し違う形で業務やイベントのネタ(の裏側)として使っていたことがあったのですが、埋もれてしまうのはもったいない気がしたので公開しちゃいます。

Node-REDFX (外国為替)情報を取得するフローを作りました。FX というのは例えば USDJPY だと USD と JPY 、つまり米ドルと日本円の関係です。「1ドル=107円23銭」みたいなやつですね。これの EURUSD (ユーロドル)やら EURJPY (ユーロ円)やら AUDJPY (豪ドル円)やら、、主に日本円が絡む通貨ペアを中心に 20 ペアの情報を1分おきにリアルタイムで取得するものです。

フローはこちらで公開しています:
https://flows.nodered.org/flow/9d045f691b6d7c5cb3259c197ad365d0

2020060105



このページ内のフロー定義を "Copy" して、Node-RED 環境に「クリップボードから読み込み」するだけでフローが再現できます。フロー1本だけの、それも標準ノードの組み合わせだけで構成されているシンプルな内容です。動く条件は「Node-RED 環境がインターネットに接続されていること」だけでいけると思います:
2020060101


↓ペースト後、こんなフローのタブが作られていれば成功:
2020060102


あとはこのまま「デプロイ」すれば1分おきに inject ノードが動き出し、取得した FX 情報を debug タブに出力し続けます:
2020060103


1回実行した時の debug タブの様子はこんな感じです。_id に実行時の日付時刻が入り、あとは通貨ペアとその瞬間の価格がまとめて出力されます:
2020060100



公開しているフローではこれだけ(debug タブに出力するだけ)ですが、IBM Cloud 内の Node-RED として動いている環境であれば、バインド済みの Cloudant out ノードをフローの最後に追加して、DB 名を指定するだけで出力される情報を1つのレコードとして DB に格納する所まで簡単に実現できます。他の環境でも各種データベースノードに渡すことで取得データの DB 格納ができます:
2020060104


中身は inject node が一分ごとに発火してオープンな API を使って FX 相場を取得し、(Cloudant DB に格納する前提での)JSON フォーマットに変換して debug ノードに渡す、というものです。FX は24時間相場が動くので、1日に 60 * 24 = 1440 データ集まります。(データ量に気をつけながら)1ヶ月程度動かしっぱなしにしておくとそこそこの為替情報データベースができあがります。シンプルですが API やフォーマットを変えることで応用範囲が広くなりそうだと思っています。

本来は集まったデータをグラフ表示したり、上下動の予測をしたり、、、といった使いみちになると思っています。サンプルではない実データを簡単に集めることができるので、説得力のあるデモアプリに応用しやすいと思っています。興味ある方は使ってみてください。


GitHub が提供をはじめた CI/CD 機能である GitHub Actions を使って IBM Cloud の IKS(IBM Kubernetes Services) にアプリケーションをデプロイできることを確認したので、一連の手順を紹介します。


【何をする?】
簡単に言うと、GitHub のリポジトリにアプリケーションのソースコードをコミット&プッシュすると、その最新コードのアプリケーションが IBM Cloud 内の Kubernetes サービスへ自動デプロイされて公開される、ということを GitHub 内の機能だけで実現します。

なお、GitHub Actions は GitHub の無料アカウントで使える機能であることに加え、IBM Cloud の IKS も(クレジットカード登録が必要な BASIC アカウントに切り替える必要はありますが)Kubernetes のシングルワーカーノードが 30 日間無料で利用できます。 以下に紹介する内容は全て無料で試すことができる内容です。

では以下に IKS の準備、GitHub の準備に続けて実際にアプリケーションコードをコミットして IKS 上で動かす所までの手順を紹介します。


【IKS の準備】
IBM Cloud で IKS サービスを作成します。IBM Cloud にログインします。ライトアカウントの場合は IKS が利用できないため、クレジットカードを登録して BASIC アカウントに切り替えるか、または新たにアカウントを作成して BASIC アカウントに切り替える必要があります。

BASIC アカウントでログイン後、画面右上の「リソースの作成」ボタンをクリックします:
2020052701


作成するサービスを一覧から選択します。画面左メニューから「サービス」-「コンピュート」を選択し、画面右の一覧から "Kubernetes Service(以下 IKS)" を選択します:
2020052702


IKS は有償版と無償版(30日経過後に削除)があります。以下は無償版である「無料クラスター」を選択している想定で紹介を続けます。クラスター名は "mycluster" 、リソースグループは "Default"(いずれも既定値)として画面右の「作成」ボタンをクリックします:
2020052703


ここから IKS 環境の作成が始まります。操作できる状態になるまでしばらく(数10分程度)かかります:
2020052704


この IKS の準備をしている時間を使って、この後の作業で利用する API キーを用意しておきます。画面右上のメニューから「管理」を選び、「アクセス(IAM)」を右クリックしてリンクを新しいタブで開く形で(つまり別ウィンドウや別タブで開く形で)選択します:
2020052706


別ウィンドウでアクセス設定画面が開いたら、画面左メニューで「API キー」を選び、「IBM Cloud API キーの作成」ボタンをクリックします:
2020052707


ダイアログが表示されるので API キーの名称(任意ですが、例えば "API Key for GitHub Actions" など)を入力して「作成」します:
2020052708


正しく実行できると以下のような画面になります。作成された API キーはマスクされ、表示されていません。この画面をこのまま閉じてしまうと作成された API キーの内容を再度確認することはできなくなるため、ファイルでダウンロードしておくか、クリップボードにコピーしておくか、目のアイコンをクリックして、マスクを外して表示し、その内容をどこかに保存しておく必要があります:
2020052709


目のアイコンをクリックするとマスクがはずれ、API キーの値を確認することができます。繰り返しますが、このダイアログを消すと API キーを再確認することはできません。忘れてしまった場合は再度 API キーを新規作成する必要がある点に注意してください。なんらかの方法で API キーの内容を再確認できるようこの内容を保存しておきます(後で使います):
2020052710


あらためて IKS サービスの作成状況を確認しておきましょう。「ファイナライズ中」と出ていればあと少しです。。。:
2020052711


しばらく待って全ての準備が完了すると、下図のように「通常」というステータスに変わります。この状態になっていれば IKS 上にアプリケーションをデプロイするための準備が整ったことになります:
2020052712


この画面を離れる前に Web 端末の準備もしておきます。この IKS で用意する Kubernetes 環境はローカルマシンの kubectl などから操作することも可能ですが、kubectl の環境を持っていない人でもブラウザ画面から利用できるターミナル機能が用意されており、こちらを使うことでローカルインストールや環境設定も不要で利用することができるようになって便利です。

Web 端末を利用するには IKS 画面右上の「Actions...」と書かれた箇所をクリックし、メニューから「Web 端末」を選択します:
2020052705


初めてこの操作をした場合はインストールができていないため以下のようなダイアログが表示されます。「インストール」をクリックして数分お待ち下さい:
2020052713


Web 端末のインストールが出来た後に改めて「Actions...」-「Web 端末」を選択すると、画面内にターミナル機能が現れ、ここから kubectl コマンドや IBM Cloud への命令を実行する ibmcloud コマンドを利用することができるます。画面が小さくて不便な場合は(別タブに)最大化して利用することもできます:
2020052714


この Web 端末を使って IBM Cloud CR(Container Registry) の名前空間をセットアップしておきます(後で使います)。まず "ibmcloud login" と入力します。IBM ID とパスワードの入力が促されるので入力し、Web 端末で IBM Cloud にログインします:
$ ibmcloud login

一度この時点で CR の名前空間一覧を確認しておきます。確認するためのコマンドは "ibmcloud cr namespaces" で、初めて実行した場合は1つも定義されていないという結果となるはずです:
$ ibmcloud cr namespaces

改めて名前空間を作成します。ユニークな名前空間名を指定して "ibmcloud cr namespace-add (名前空間)" を実行します:
$ ibmcloud cr namespace-add (名前空間名)

名前空間名は他の人が使っているものを指定することはできません(エラーとなります)。自分の場合は "ibmcloud cr namespace dotnsf-ns" と入力しました。実際に実行する場合はここで他の人が使っていないものを指定して実行してください(エラーとなる場合はエラーにならずに実行完了するまで繰り返して実行してください)。

最後に CR の名前一覧表示コマンドを再度実行し、直前のコマンドで作成した名前空間が一覧に含まれていることを確認してください:
$ ibmcloud cr namespaces

自分の上記例ではこんな感じになりました。この名前空間名も後で利用します:

2020052701


IKS の準備作業はこれで終わりです。


【アプリケーションおよび GitHub の準備】
次に IKS にデプロイするアプリケーションと GitHub 側の準備を行います。まずはデプロイするアプリケーションを準備して Docker 対応(Dockerfile の準備)します。ここは実際に IKS にデプロイして使ってみたいアプリがある場合は個別に用意していただいても構いません。

一応サンプルとしてシンプルな Web アプリケーションを用意しました。自分でアプリケーションを用意しない場合はこちらをお使いください:
https://github.com/dotnsf/hostname_githubactions_iks


このサンプルを使う場合は、まず GitHub にログインした上で上記 URL を開きます。そして画面右上の "fork" を選択し、自分自身のリポジトリとして複製してください:
2020052702


成功すると https://github.com/XXXXX/hostname_githubactions_iks というリポジトリができあがります(XXXXX 部分は各ユーザー個別の ID 名)。以降はこのリポジトリを使って GitHub Actions を利用します。まずこの URL を指定してリポジトリの内容をローカルに clone しておきます(XXXXX 部分は自分の ID に置き換えて実行してください):
$ git clone https://github.com/XXXXX/hostname_githubactions_iks

これでサンプルアプリケーションのソースコードがローカルファイルとしてクローンされ、ローカルファイルとして参照することができるようになりました。簡単にアプリケーションの内容を紹介しておくと、このサンプルアプリケーションは Node.js で実装されており、 GET / という HTTP リクエストに対して /etc/hostname ファイルの内容を text/plain でそのまま返すだけの機能を持っています。本体である app.js ファイルの全容は以下(これで全部)で、実質20行足らずの実装です。またポート番号は 8080 番で固定しています:
//.  app.js
var express = require( 'express' ),
    fs = require( 'fs' ),
    app = express();

app.get( '/', function( req, res ){
  res.contentType( 'text/plain; charset=utf-8' );
  fs.readFile( '/etc/hostname', "utf-8", function( err, text ){
    if( err ){
      res.write( JSON.stringify( err, 2, null ) );
      res.end();
    }else{
      res.write( text );
      res.end();
    }
  });
});

var port = 8080;
app.listen( port );
console.log( "server starting on " + port + " ..." );


この app.js と、依存ライブラリや起動コマンドが記述された package.json や、コンテナ対応のための Dockerfile などが含まれたアプリケーションとなっています。

繰り返しますが、実際に IKS にデプロイするアプリケーションは Docker 対応できていれば他のものを使っても構いません。ただしその場合はこのサンプルの .github/ フォルダ以下をまるごとそのアプリケーションプロジェクトにコピーしておいてください(実質的に .github/workflows/iks.yml ファイル1つだけのフォルダで、この iks.yml が Github Actions を IKS で使うためのワークフローを定義しています)。

iks.yml ファイルの中身はこの後で参照しますが、このファイルは Github のプロジェクトのシークレット情報を参照して動くよう定義されています。したがって必要なシークレット情報を Github プロジェクト内にあらかじめ定義しておく必要があります。

そのための設定を行います。 https://github.com/XXXXX/hostname_githubactions_iks を開き、"Settings" タブを選んで左メニューから "Secrets" を選択します。このプロジェクトに設定されたシークレット情報の一覧が表示されますが、最初は空のはずです。ここにシークレット情報を追加するため "New secret" ボタンをクリックします:
2020052703


シークレット情報は名前(Name)と値(Value)の組で定義します。まずは "IBM_CLOUD_API_KEY" という名前のシークレットを定義します。この値としては上述した IBM Cloud 利用時に作成してダウンロードするかクリップボードに保存した IBM Cloud API Key の値を入力します。入力後に "Add secret" ボタンをクリックして保存します:
2020052704


同様にしてもう1つ、"ICR_NAMESPACE" という名前で、 IBM Cloud CR の名前空間として作成した名称(上記例では dotnsf-ns ですが、個別に作成した時の値)を入力し、最後に "Add secret" をクリックします:
2020052705


つまりプロジェクトのシークレット情報として IBM_CLOUD_API_KEY と ICR_NAMESPACE の2つが定義されている状態にします。これで GitHub プロジェクト側の準備は完了です:
2020052706


最後に Github Actions のワークフロー定義を各自の内容に合わせて書き換えます。プロジェクト内の .github/workflows/iks.yml ファイルをテキストエディタで開きます。なおこのファイルの内容は以下のプロジェクトに含まれて提供されていたものをベースにしています:

https://github.com/IBM/actions-ibmcloud-iks


iks.yml を開き、20 行目以下(env: で始まる行以下)の値を編集します。といっても自分の独自アプリケーションではなく https://github.com/dotnsf/hostname_githubactions_iks からフォークしたプロジェクトのアプリケーションを使う場合はほぼそのままでも動くはずです:
2020052707


編集の必要な箇所があるとすれば以下です:
変数名設定内容既定値
IBM_CLOUD_REGIONIBM Cloud で利用する IKS のリージョン(地域)us-south
REGISTRY_HOSTNAME内部で利用する Docker Hub のホスト名us.icr.io
IMAGE_NAMEDocker イメージを保存する時の名称hostname
IKS_CLUSTERIKS 作成時に指定したクラスタ名mycluster
DEPLOYMENT_NAMEDocker イメージを IKS にデプロイする時の DEPLOYMENT の名称hostname
PORTアプリケーションが HTTP アクセス時に LISTEN するポートの番号
8080


ここまでの作業で hostname_githubactions_iks プロジェクト(Github にコミットするプロジェクト)のファイルに変更を加えている場合はこれで準備完了です。加えていない場合はコミットに変化を加えるというだけの目的でいずれかのファイルに挙動に支障のない変更を加えておいてください。例えば README.md ファイルの最後に空の1行を追加する、などでも構いません(苦笑):
2020052708


これで全ての事前準備が整いました。


【GitHub Actions の実行】
ではこのプロジェクトを Github にコミット&プッシュします:
$ cd hostname_githubactions_iks

$ git add .

$ git commit -m 'README.md updated.'

$ git push


Push の成功と同時に Github Actions が実行されます。リポジトリのページ(https://github.com/XXXXX/hostname_githubactions_iks )を開き、"Actions" タブを選択すると、コミットコメントの横にクルクル回るアイコンが表示され、Github Actions に定義された内容(iks.yml の内容)に従ってアプリケーションイメージが内部 Docker Hub に登録され、そこから IKS へデプロイされていきます:
2020052709


しばらくすると一連の作業が完了します。下図のように緑のチェックマークが表示されていればコマンドが成功しています(赤いバツは失敗):
2020052710


この箇所をクリックすることでワークフローで実行された内容の詳細を確認したり、(失敗している場合は)どこで失敗しているかを確認することもできます:
2020052700


この時点でアプリケーションは IKS 内にデプロイされ動いており、パブリックに公開されています。では実際に動いているアプリケーションにアクセスしてみたいのですが、そのためにはアクセスするための情報(IP アドレスおよびポート番号)を見つける必要があります。

まず公開されているパブリック IP アドレスは IBM Cloud ログイン後のダッシュボードから確認することができます。作成した IKS のワーカーノードを表示し、稼働しているサービスのパブリック IP を確認します。これが外部アクセス用の公開 IP アドレスとなっています:
2020052701


またポート番号は Web 端末から "kubectl get svc" を実行し、サービス名(iks.yml で指定したデプロイ名、上述の例だと hostname)の PORT(S) 列を参照します。 "80:*****/TCP" と表示されている ***** 部分(下図の場合は 32284)がサービスにアクセスするためのポート番号となります:
2020052702


これらを組み合わせてウェブブラウザまたは curl コマンドなどで http://(IP アドレス):(ポート番号) にアクセスします。下図の例では http://173.193.112.74:32284/ へアクセスしています。またその実行結果として(コンテナの /etc/hostname の中身である hostname-59cb7b958f-lwv52 という値が表示されています。この結果は実行環境によって異なりますが、実際に稼働しているコンテナから取得した値となっています)。実際の稼働環境にアクセスして挙動を確認することもできました:
2020052703


この時点で IKS 上で稼働しているので、インスタンスのスケールイン/スケールアウトといった操作も可能です。

またこの状態から更にアプリケーションのソースコードを改良するなどした上で、再度 git commit & git push すると同じワークフロープロセスが動き、自動的に IKS 内に最新コードのアプリケーションがデプロイされる、という CI/CD 環境が構築できました。


【デプロイしたポッド等を削除する場合】
最後に環境を削除する手順を紹介します。IKS そのものごと削除する場合は(IBM Cloud のメニューから IKS ごと削除すればよいので)ある意味で簡単ですが、IKS を残して IKS 内にデプロイしたアプリケーション環境を削除する場合の手順を紹介します。

まず Web 端末で "kubectl get all" を実行して、ポッドやサービス、デプロイメントの情報を確認します:
2020052704


この実行結果から hostname 関連のポッド、サービス、デプロイメントを削除します。Web 端末で続けて以下のコマンドを実行します(service/kubernetes のサービスは IKS そのものなので削除しないよう気をつけてください):
$ kubectl delete deployment hostname

$ kubectl delete service hostname

$ kubectl delete pod hostname-59cb7b958f-lwv52

最後にもう一度 "kubectl get all" を実行して、hostname 関連のものが残っていないことを確認します:
2020052705


上記のような結果になれば無事に削除できました。
 

このページのトップヘ