IBMのソリューションやソフトウェアに対し、そのテクニカルコミュニティーにおいて高度な貢献をしたエンジニアを表彰する制度「IBM Champions」。今回はIBM Champion for Cloud 2019に選出された平岡大祐氏に、その知見・ノウハウを体感できる記事を執筆していただいた。昨今のDXトレンドなどについて聞いたショートインタビューとともに、3回にわたって「Red Hat OpenShift on IBM Cloud」の実践的な活用方法をお届けする。最終回はOpenShiftを使ったCI/CD(継続的インテグレーション/継続的デリバリー)について。
DX(デジタルトランスフォーメーション)トレンドが進展し、ビジネスが「ITを使った体験価値の競争」に変容して久しい。テクノロジーはビジネスのコアとなり、それを使いこなすエンジニアこそが、ビジネスの推進役となる時代が到来したといえるだろう。
そうした中、IBMが主催しているのが「IBM Champions」だ。IBMのソリューションやソフトウェアに対し、年間を通してテクニカルコミュニティーに優れた貢献をしたエンジニアを表彰する制度で2008年に創設。2018年までにグローバルで650人、うち日本人は51人が選出されている。開発者、ビジネスリーダー、経営層など、全世界のITに携わる人に向けたインフルエンサーとして認定され、「IBM Analytics Champions」「IBM Cloud Champions」「IBM Collaboration&Talent Champions」「IBM Power Systems Champions」「IBM Storage Champions」「IBM Z Champions」の6部門で表彰。IBMのグローバルイベント、公式サイト、ブログなどを通じた意見発信の機会が与えられる。
今回はIBM Champion for Cloud 2019に選出された平岡大祐氏に、その知見・ノウハウを体感できる記事を執筆していただいた。昨今のDXトレンドなどについて聞いたショートインタビューとともに、3回にわたって「Red Hat OpenShift on IBM Cloud」の実践的な活用方法をお届けする。手を動かして“最先端の視点”を体感してはいかがだろうか。
IBM Champion for Cloud 2019
2002年からエンジニアとして、業務系、基幹系システム、プロダクトの設計、開発、運用などさまざま業務に従事。2016年の夏に2カ月でIBM CloudのベアメタルサーバにOpenShift環境を構築し、2017年1月から本番環境で稼働させ、運用する業務を経験。以降、コンテナやOpenShiftの業務を多く経験するようになる。2018年3月刊行の『コンテナ・ベース・オーケストレーション Docker/Kubernetesで作るクラウド時代のシステム基盤』(翔泳社)に、OpenShiftに関する章の共著で参加。Red Hat認定資格「Red Hat Certified Specialist in OpenShift Administration」を取得している。
―― アジャイル、DevOps、CI/CDの必要性とは?
Red Hat OpenShift on IBM Cloudでのアプリケーション開発の前提となる「コンテナ」は、リリーススピードを速めるアジャイル、DevOps、CI/CDを実践するための一要素です。DXを実現するためには、リリーススピードを速めることが欠かせないのは言うまでもないと思います。
―― では、これまでアジャイル、DevOps、CI/CDを阻んできたものとは何か?
今までの経験でいうと、外注することによるリードタイムの増加もあると思います。なぜ外注が増えたのかについては、IBMの方が言うには、テクノロジーが分かっているIT部門が、テクノロジーの言葉をビジネス層、経営層に分かる言葉で説明できないから、外注してしまう。外注側はビジネス上ウオーターフォール的な開発体制を取らざるを得ない時代だったということもあるでしょう。でも、リリーススピードと自動化が求められている今の時代は変わらざるを得ないですよね。
―― エンジニアがビジネスに寄与するために必要なこととは?
アジャイル、DevOps、CI/CDに加え、これまで紹介してきたようなコンテナやマイクロサービスといった技術を活用できることがビジネスへの寄与に必要になると思います。コンテナやマイクロサービスについては、若いエンジニアのものというイメージがあるかもしれませんが、マイクロサービス化に必要なドメイン駆動設計ができる人、つまり業務を整理できるエンジニアは昔からJavaやオブジェクト指向に触れてきた人たちだと思います。40歳を過ぎた人たちこそがヒーローになれるのではないでしょうか。
今回の記事では、OpenShiftを使ったCI/CD(継続的インテグレーション/継続的デリバリー)について見ていただきたいと思います。
※以下は日本アイ・ビー・エムから提供されたコンテンツを、許諾を得て転載したものです。このため、用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。
IBM Champion for Cloud 2019の平岡です。3カ月にわたってRed Hat OpenShift on IBM Cloudの実践的な活用方法について連載しました。
この3回目の記事がこの連載の最後の記事となりますが、今回は、より実践的に開発/検証/本番環境へのアプリケーションのリリースを想定した「OpenShiftでDevOps、CI/CD(継続的インテグレーション/継続的デリバリー)について」です。
本題に入る前に少し前回の内容に戻ってみましょう。
前回の記事では私たちはExample HealthのOpenShiftによるJava EEアプリケーションのモダナイゼーションに成功しました。
これからは、その後の話になります。Red Hat OpenShift on IBM Cloudに移行した結果、Example Healthは容易に機能拡張できるようになりました。そして次々にシステムを拡大して新しいサービスを追加していきます。その一つが健康記録管理者用のPHPアプリケーションのCode Patternsです。 このCode Patternsを自分のパソコンで試すことができるようにQiitaに投稿しました。是非お試しください。
順風満帆に見えたExample Healthですが、サービスが増えるにつれアプリケーションのリリースサイクルが遅くなっていく問題に直面します。Example Healthではアプリケーションの開発は開発担当、アプリケーションのリリースは運用担当と役割分担があり、運用担当はこれまでアプリケーションのリリースの度に開発担当が書いたExcel手順書に書かれた通りに実行するのが慣例でした。実は運用担当はモダナイゼーションの旅に取り残されていて、サービスが増えれば増えるほど、Excel手順書が増え、リリースのための作業そのものがボトルネックになっていたのです。開発担当、運用担当の間でのExcel手順書のキャッチボールは徐々にフラストレーションがたまり関係が悪化していきます。そして、ある日、運用担当のオペレーションミスでリリース事故が発生するのです。
このまま運用担当と開発担当の壁がある状態ではExample Healthのモダナイゼーションは成功したとは言えません。アーキテクチャに見合った組織改革も必要ですが、アプリケーションのリリースについてもモダナイゼーションが必要です。
説明が長くなりましたが、この問題を解決することが今回のメインテーマになります。
初めに、DevOpsやCI(継続的インテグレーション)をやるために必要なOpenShiftのビルドについて説明します。
次に開発環境でビルドしたコンテナイメージを使って検証/本番環境へのアプリケーションのリリースを、「oc」コマンドを使った手動オペレーションで行う方法、次にJenkinsを使って自動で実施する方法を順に試したいと思います。
OpenShiftの標準的な機能のみを使ってDevOpsやCI/CD(継続的インテグレーション/継続的デリバリー)が実現できるってところがポイントです。
それでは、実際に試していきましょう。
GitHubのリポジトリをクローンします。クローンするとpatientuiフォルダが作成されます。
$ git clone https://github.com/daihiraoka/patientui.git $ cd patientui $ ls README.md patientui-all.yaml patientui_dc.yaml patientui_dc_tok05.yaml patientui_is.yaml patientui_svc.yaml
patientui-all.yamlは、2回目の記事でpatientuiという名称で作成した患者用UI(ユーザーインターフェイス)の定義をエクスポートしたものです。
エクスポートは「oc get」コマンドを実行して取得できます。
$ oc get --export=true BuildConfig,DeploymentConfig,Service,ImageStream,Route \ patientui -n health -o yaml > patientui-all.yaml
その他のファイルはpatientui-all.yamlを基に私が作成したこの後使用するテンプレートです。
OpenShiftのビルドの仕組みの一つにSource-to-Image(S2I)というアプリケーションのソースコードを使って新しいコンテナイメージを作成させるフレームワークがあります。
Source-to-Image(S2I)はS2I Scriptというソフトウェアが準備されたベース(コンテナ)イメージにアプリケーションのソースコードを挿入し、アプリケーションのコンテナイメージを作成します。このフレームワークの最大のメリットはソースコードとベースイメージが分離されるので、開発担当はソースコードを書くこと、運用担当はベースイメージの保守と役割を明確に分けることができることです。ベースイメージからソースコードが分離していることはバージョンアップやパッチ適用など組み合わせ検証も容易になりますね。
実は、Source-to-Image(S2I)は既に1回目の記事で、ブラウザ操作でPHPのバージョンとアプリケーションのソースコードを指定して「create」ボタンをクリック、
2回目の記事の患者用UIでは、Node.jsのベースイメージとアプリケーションのソースコードを指定して「oc new-app」コマンドを実行した後に始まるビルドの中でSource-to-Image(S2I)を使ってコンテナイメージを生成していました。
$ oc new-app openshift/nodejs-10~https://github.com/daihiraoka/node-s2i-openshift.git --name='patientui' --context-dir='/site'
DevOpsも考慮されているSource-to-Image(S2I)はよく考えられてると思いませんか?
Source-to-Image(S2I)のS2I Scriptの動作はベースイメージの起動(docker run)でS2I Scriptの処理が始まります。
S2I Scriptはダウンロードしたソースコードをtarでベースイメージに流し込んだものをdocker commit/pushでアプリケーションのコンテナイメージを作成します。S2I Scriptはシェルスクリプトで書かれていて、ダウンロードしたJavaのソースコードをmavenでビルドするなど、みなさんの配信プロセスを追加することもできますよ。
従来のDockerfileのビルドでは1行が1レイヤーとして積み重ねになるのに対してS2I Scriptを使うことで1つのレイヤーの追加でコンテナイメージが作成されるのでビルドスピードやイメージのサイズが改善されます。tarでソースコードを流し込むのもビルドスピードが早くなる仕組みの一つです。
次にみなさんの理解を高めるためにSource-to-Image(S2I)のイメージ図とビルド設定(BuildConfig)は同じなのか確認しましょう。
(2)sourceセクションでアプリケーションのソースコードを指定します。 患者用UIではGitHubのリポジトリを指定しました。
(3)fromセクションでベースイメージを指定します。2回目の記事では患者用UIのベースイメージをopenshiftプロジェクトにインポートしたので、ここではopenshiftプロジェクトのnodejs-10:latestを指定しています。
(1)outputセクションでは、ビルドで生成するコンテナイメージを指定します。 今回のビルドで生成されたコンテナイメージはpatientui:latestで作成されます。
(2)アプリケーションのソースコードを(3)ベースイメージに挿入して(1)アプリケーションのコンテナイメージを生成になるのでSource-to-Image(S2I)のイメージ図と同じになっていることがわかりますよね。
次に自動でビルドが始まるために必要なトリガーの設定です。
(4)GitHub、GitLab、BitbucketまたはGeneric Webhookを使用したWebhookトリガーを定義できます。WebhookのURLが発行されるのは、BuildConfigがOpenShiftに作成された後なので、ここで設定できるのはsecretの鍵のみです。
(5)type: ConfigChangeはビルド設定(BuildConfig)に変更が発生した場合にビルドが自動開始します。(初回登録を含む)
type: ImageChangeはfromに定義したベースイメージに変更が起こった場合にビルドを自動開始します。
OpenShiftにはトリガーがあるので、ソースコードをコミットするとWebhookトリガーで自動的にビルドが始まります。後述のデプロイ設定(DeploymentConfig)にもトリガーがあります。トリガーのおかげでアプリケーション開発者はOpenShiftを触れることなく、ソースコードの変更を確認することができます。この繰り返しはCI(継続的インテグレーション)になります。標準の機能でCIができるってすごくないですか?運用担当者もベースイメージをアップデートするとImageChangeトリガーから自動でビルドが始まり、CIすることができて検証が楽になりますよ。
今回はOpenShiftのイメージプロモーションと呼ばれるImageStreamのタグを使ったアプリケーションのリリースを開発環境の患者用UIアプリケーションを使って検証/本番環境にリリースを行います。初めに「oc」コマンドを使った手動オペレーションで手順を確認します。そして、その手順をJenkins Pipelineにしてリリースを自動化したいと思います。
図ではすでに開発環境(healthプロジェクト)は完成しているので、検証環境と本番環境を作成した後に(5)から(10)の手順を行うのみです。
ここでのポイントは、コンテナイメージのビルドが開発環境にしかないことです。1つのコンテナイメージを開発/検証/本番環境と開発サイクル全体を通して使用することは、各環境間での変化が少ない、もしくはまったくないということです。
これまで、ある環境ではバグが出力され、他の環境では出力されなくて困った!という経験はみなさん少なからずあると思います。仮想マシンをクローンしたとしても、たとえAnsibleのような自動構成ツールを使って、同じ手順で、各環境でビルド・デプロイしたとしても、ごくわずかなのでしょうがライブラリやバイナリの差が発生するからです。
上記の問題がなくなるのが、コンテナを使うことのメリットの一つですね。
1.検証環境(health-testing)のプロジェクトを作成します。
$ oc new-project health-testing
2.検証環境から開発環境のコンテナイメージを参照できるようにsystem:image-pullerロールを検証環境のdefault(全てのPod)サービスアカウントに追加します。
- 検証環境(health-testting) $ oc policy add-role-to-user \ system:image-puller system:serviceaccount:health-testing:default \ -n health role "system:image-puller" added: "system:serviceaccount:health-testing:default"
事前準備で用意したYAMLファイルを使って順番にImageStream、DeploymentConfig、Serviceを作成します。
3.ImageStreamの作成
まず、開発環境のImageStreamを確認します。
- 開発環境 $ oc get is -n health NAME DOCKER REPO TAGS UPDATED patientui docker-registry.default.svc:5000/health/patientui latest 7 days ago
patientuiという名前でlatestタグがあることがわかります。このコンテナイメージを使って検証環境へのリリースを行います。
そして、開発環境のコンテナイメージを格納するために検証環境にImageStreamを作成します。
$ oc create -f patientui_is.yaml imagestream.image.openshift.io/patientui created $ oc get is NAME DOCKER REPO TAGS UPDATED patientui docker-registry.default.svc:5000/health-testing/patientui
patientuiというImageStreamが作成されましたが、この段階では、コンテナイメージは展開されていないのでTAGSとUPDATEが何も記載されていません。patientuiという空っぽの箱が作成されたと考えてください。
4.デプロイ設定(DeploymentConfig)を登録します。
GitHubのリポジトリからクローンしたデプロイ設定(DeploymentConfig)はpatientui_dc.yamlとpatientui_dc_tok05.yamlの2つあります。この2つのデプロイ設定(DeploymentConfig)の差分はnodeSelectorの設定がpatientui_dc_tok05.yamlにあることです。
$ diff patientui_dc.yaml patientui_dc_tok05.yaml 10a11,12 > nodeSelector: > failure-domain.beta.kubernetes.io/zone: tok05
nodeSelectorはPod(コンテナ)を起動するワーカーノードを指定する設定です。「oc get node」コマンドに--show-labelsオプションを追加して実行し出力されたワーカーノードのLABELSを使って設定します。
検証環境ではPod(コンテナ)が起動するデーターセンター(ゾーン)をtok05のみに指定したかったので図(2)Keyを"failure-domain.beta.kubernetes.io/zone"、Valueを"tok05"の追加したpatientui_dc_tok05.yamlを作成しました。patientui_dc.yamlはnodeSelectorの設定はないので、全てのワーカーノードにPod(コンテナ)は起動します。ちなみに、ワーカーノードを1つ指定したい場合は、図(1)keyを"kubernetes.io/hostname"、Valueを"10.192.17.136"とIPアドレスを指定して設定することができますよ。
では、patientui_dc_tok05.yamlを登録します。
$ oc create -f patientui_dc_tok05.yaml $ oc get dc NAME REVISION DESIRED CURRENT TRIGGERED BY patientui 0 3 0 config,image(patientui:latest)
DeploymentConfigを登録した時点では、Pod(コンテナ)の要求(DESIRED)は3ですが、この時点では検証環境にはコンテナイメージはないため現在動作しているPodの数(CURRENT)は0になっています。TRIGGERED BYの列でimage(patientui:latest)がありますが、patientuiというImageStreamのlatestタグに更新があったらトリガーが発動するという意味です。
これでImageStreamとDeploymentConfigが作成され、デプロイできる準備ができました。
5.「図:検証/本番環境へのアプリケーションのリリースの簡素化と自動化概要(5)タグ付けの手順」
oc tag image-name:tag1 image-name:tag2の書式でタグ作成します。今回、検証環境のタグ名は、バージョン管理したいので1.0-1としました。
- 開発環境から検証環境へのタグ付け $ oc tag health/patientui:latest health-testing/patientui:1.0-1 Tag patientui:1.0-1 set to health/patientui@sha256:803891d56baf51695b9473c948210725c699d9c401a4c602f6233180a457c339.
「oc tag」コマンドの出力はImageStream: patientuiのタグ:1.0-1はhealthプロジェクトのImageStreamImageであるpatientui@sha256:803891d56baf51695b9473c948210725c699d9c401a4c602f6233180a457c339にセットされたという意味です。
ImageStreamImageとはImageStreamでコンテナレジストリにあるコンテナイメージを一意に識別するための名前で<ImageStream名> @ <sha256のハッシュ値> で表現します。sha256のハッシュ値は「docker image --digests」で出力されるDIGEST値を使っています。
そして検証環境のImageStreamを確認するとTAGSに1.0-1が追加されたことが確認できました。
$ oc get is -n health-testing NAME DOCKER REPO TAGS UPDATED patientui (省略):5000/health-testing/patientui 1.0-1 35 seconds ago
DeploymentConfigを確認するとImageStreamのpatientui:latestでデプロイが始まるため、現在動作しているPodの数(CURRENT)は0のままです。
$ oc get dc NAME REVISION DESIRED CURRENT TRIGGERED BY patientui 0 3 0 config,image(patientui:latest)
6.「図:検証/本番環境へのアプリケーションのリリースの簡素化と自動化概要(6)タグ付けの手順」
それではImageStreamのタグを1.0-1からlatestにタグ付けして、デプロイが実行されることを確認しましょう。
- 開発環境(1.0-1からlatest) $ oc tag health-testing/patientui:1.0-1 health-testing/patientui:latest Tag patientui:latest set to health-testing/patientui@sha256:803891d56baf51695b9473c948210725c699d9c401a4c602f6233180a457c339. $ oc get is -n health-testing NAME DOCKER REPO TAGS UPDATED patientui (省略):5000/health-testing/patientui latest,1.0-1 14 seconds ago
ImageStreamにはlatestタグが追加されました。
7.DeploymentConfigを確認するとImageChange(patientui:latest)トリガーが動作して現在動作しているPodの数(CURRENT)は3に変わりました。
$ oc get dc NAME REVISION DESIRED CURRENT TRIGGERED BY patientui 1 3 3 config,image(patientui:latest)
8.Pod(コンテナ)を確認します。
$ oc get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE patientui-1-5rmzv 1/1 Running 0 34s 172.30.138.197 10.193.80.235 patientui-1-fftpr 1/1 Running 0 34s 172.30.138.209 10.193.80.235 patientui-1-rdchs 1/1 Running 0 34s 172.30.138.241 10.193.80.235
Pod(コンテナ)が3つ、nodeSelectorで指定したTOK05のワーカーノード(IP 10.193.80.235)で起動していることがわかります。
9.外部から接続できるようにServiceとRouteを作成します。
$ oc create -f patientui_svc.yaml service/patientui created $ oc get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/patientui ClusterIP 172.21.107.238 <none> 8080/TCP 1m $ oc expose svc/patientui route.route.openshift.io/patientui exposed $ oc get route NAME HOST/PORT PATH SERVICES PORT patientui patientui-health-testing.<省略>.appdomain.cloud patientui 8080-tcp
10.ブラウザでホスト名をアクセスすると患者用UIのログイン画面が出力されました。
これまでの手順からOpenShiftを使うとImageStreamのタグの作成だけでコンテナイメージを異なる環境へリリースできることがわかっていただけたと思います。みなさんの従来使っている手順に比べてみると大幅に時間が短縮されませんか?タグの作成だけなので簡単ですし、1回のビルドで生成されたコンテナイメージを他の環境でも使用することができるので各環境間での変化が少ない、もしくはまったくないのもいいですよね。
ちなみにDockerではタグをつけるのは「docker tag」コマンドですが、タグをつける時は、コンテナイメージを直接操作しています。一方、ImageStreamではコンテナイメージを参照しているだけなので、「oc tag」コマンドでタグをつける時は、ImageStreamの中で解決するのでコンテナイメージを操作していないので変化がありません。こういう所もKubernetesにはないOpenShiftの強みなのです。
開発環境(health)のlatestと検証環境のlatestでタグ付けすれば、タグ付けした瞬間にデプロイが始まって簡単なのですが、latestタグが更新されるだけで、履歴が残りません。そのため、1.0-1のようにバージョンを使って、タグ付けの手順は1つ増えますが、ImageStreamのタグと履歴管理機能を使って、下図のようにリリースする場合は「最新のバージョンのタグをlatestにタグ付け」、ロールバックする場合は「古いバージョンのタグをlatestにタグ付け」とリリース・ロールバックはImageStreamのタグで統一、全てのリリースは記録されるという形にしたのです。
本番環境へのデプロイ設定の手順は、ほとんど同じため簡単に紹介します。
1.本番環境(health-production)プロジェクトを作成します。
$ oc new-project health-production
2.本番環境から開発環境のコンテナイメージを参照できるようにsystem:image-pullerロールを本番環境のdefault(全てのPod)サービスアカウントに追加します。
- 本番環境(health-production) $ oc policy add-role-to-user \ system:image-puller system:serviceaccount:health-production:default \ -n health role "system:image-puller" added: "system:serviceaccount:health-production:default"
3.デプロイ設定(DeploymentConfig)を登録します。
$ oc create -f patientui_dc.yaml
4.「図:検証/本番環境へのアプリケーションのリリースの簡素化と自動化概要(8)タグ付けの手順」
「oc tag」コマンドを使用して検証環境(health-testing)と本番環境(health-production)のpatientui:1.0-1をタグ付けします。
- 検証環境(patienutui:1.0-1)から本番環境(patienutui:1.0-1) $ oc tag health-testing/patientui:1.0-1 health-production/patientui:1.0-1 Tag patientui:1.0-1 set to health-testing/patientui@sha256:803891d56baf51695b9473c948210725c699d9c401a4c602f6233180a457c339.
5.「図:検証/本番環境へのアプリケーションのリリースの簡素化と自動化概要(9)タグ付けの手順」
「oc tag」コマンドを使用して本番環境(health-production)のpatientuiのタグ1.0-1からlatestにタグ付けします。
- 本番環境(patientui:1.0-1からpatientui:latest) $ oc tag health-production/patientui:1.0-1 health-production/patientui:latest Tag patientui:latest set to health-production/patientui@sha256:803891d56baf51695b9473c948210725c699d9c401a4c602f6233180a457c339.
6.DeploymentConfigを確認するとImageChange(patientui:latest)トリガーが動作して現在動作しているPodの数(CURRENT)は3に変わりました。
$ oc get dc NAME REVISION DESIRED CURRENT TRIGGERED BY patientui 1 3 3 config,image(patientui:latest)
7.Pod(コンテナ)を確認します。
$ oc get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE patientui-1-jdt7w 1/1 Running 0 34s 172.30.121.202 10.192.17.136 patientui-1-l968s 1/1 Running 0 34s 172.30.199.21 10.212.36.4 patientui-1-wqg2l 1/1 Running 0 34s 172.30.138.240 10.193.80.235
Pod(コンテナ)が3つ、今回は NODEのIPアドレスが全て違うことからTOK02、TOK04、TOK05に均等に配置されました。
これで手動での開発環境、検証環境、本番環境のアプリケーションのリリースが終わりました。最初の一回だけは、ImageStream、DeploymentConfig、Serviceなどオブジェクトを作成する必要があるので手順は多いですが、一回作ると開発でビルドした後は、ImageStreamのタグ付けだけでリリースは終わってしまいます。簡単過ぎるくらい簡単ですよね。
OpenShiftには、JenkinsをOpenShiftで使うためにカスタマイズされたJenkinsのイメージが標準で用意されています。これまで手作業で実施した開発環境から本番環境までのアプリケーションのリリース手順をJenkins Pipelineに変えてリリースを自動化したいと思います。Jenkins Pipelineの詳細についてはOpenShift 4.2の製品ドキュメント 5.4. PIPELINE ビルドがわかりやすかったので参考にしてください。
事前準備
1.GitHubのリポジトリをクローンします。クローンするとpatientui-pipelineフォルダが作成されます。
$ git clone https://github.com/daihiraoka/patientui-pipeline.git $ cd patientui-pipeline $ ls README.md patientui-pipeline.yaml
patientui-pipeline.yamlが、今回使用するテンプレートファイルです。
テンプレートファイルは、Jenkins Pipelineビルドの設定と、healthプロジェクトの患者用UIアプリケーションの設定を参考にして作ったテンプレートを記述しています。
今回、このテンプレートファイルを使って、新たにhealth-pipelineプロジェクトを作成し、このプロジェクトにJenkinsと患者用UIのアプリケーションを立ち上げます。
このプロジェクトでビルドした患者用UIのコンテナイメージを検証環境(health-testing)、本番環境(health-production)へJenkinsのPipelineを使ってリリースを行います。
処理概要
下図では、上部が「oc」コマンドを使用して手動で行なっていたフロー、下部が、Jenkins Pipelineで行う場合のフローになります。
Pipelineの設計
今回のPipelineは5つのステージで構成されています。
environmentにはJenkinsfile内で利用する変数を定義します。
environment { version = "2.0" devTag = "${version}-${BUILD_NUMBER}" }
今回はイメージのタグ付けを行うためにdevTagの変数を使います。versionは任意の数字、手動で1.0をつけたので、今回は2.0を設定、BUILD_NUMBERはJenkins Jobのビルド番号が格納されるデフォルトの環境変数です。
Jenkins Pipelineが実行されるとdevTagは2.0-1、2.0-2、2.0-3とBUILD_NUMBERが+1加算されるのを利用して履歴管理に使います。
1.ビルド(開発環境)
stage("Build Image") { steps { script { openshift.withCluster() { openshift.withProject() { def bld = openshift.startBuild('patientui') bld.untilEach { return it.object().status.phase == "Complete" }
このステージでは開発環境(patientui-pipeline)でビルドが始まりSource-to-Image(S2I)でコンテナイメージを作成します。
スクリプトの中ではdef bld = openshift.startBuild('patientui')でpatientuiのビルドが開始し、bld.untilEach {} で ビルドのステータスが"Complete"になるまでループしてビルドが終わるのを待っています。
2.デプロイ(開発環境)
stage("Deploy Image") { steps { script { openshift.withCluster() { openshift.withProject() { def dc = openshift.selector('dc', 'patientui') dc.rollout().latest()
開発環境で作成したコンテナイメージを開発環境にデプロイします。
3.タグ付け(開発環境)履歴管理
stage("Tagging Image Development latest to devTag") { steps { script { openshift.withCluster() { openshift.withProject() { // Tag the patientui:latest image as patientui:${devTag} openshift.tag("patientui:latest", "patientui:${devTag}")
openshift.tagでImageStreamのタグを作成します。ここではImageStreamに履歴を残すために現在動作している最新のコンテナイメージであるlatestをpatientui:${devTag}でタグ付けします。
4.検証環境にデプロイ
stage("Promote Image Development to Testing") { steps { script { openshift.withCluster() { openshift.withProject() { // Tag the patientui:${devTag} image as health-testing/patientui:${devTag} openshift.tag("patientui:${devTag}", "health-testing/patientui:${devTag}") openshift.tag("health-testing/patientui:${devTag}", "health-testing/patientui:latest")
開発環境(patientui-pipeline)のpatientui:${devTag}のImageStreamを検証環境(health-testing)のpatientui:${devTag}へタグ付けして履歴管理します。
そして、検証環境へのデプロイは、ImageStreamのタグを${devTag}からlatestに移動することでイメージが更新され、自動的に新しいデプロイが開始します。
5.本番環境にデプロイ
stage("Promote Image Testing to Production") { steps { script { openshift.withCluster() { openshift.withProject('health-testing') { // Tag the patientui:${devTag} image as health-testing/patientui:${devTag} openshift.tag("patientui:${devTag}", "health-production/patientui:${devTag}") openshift.tag("health-production/patientui:${devTag}", "health-production/patientui:latest")
検証環境と似ていますが、本番環境はopenshift.withProject('health-testing')と検証環境(health-testingプロジェクト)に移動してタグ付けを行なっています。ちなみに検証環境のようにopenshift.withProject()をプロジェクト指定しない場合はJenkinsがデプロイされているプロジェクトで実行されます。
本番環境も検証環境と同様にImageStreamのタグを${devTag}からlatestに移動することでイメージが更新され、自動的に新しいデプロイが開始します。
これで準備が整いましたので、Pipelineから新しいデプロイを実行できるようにJenkinsインスタンスを起動します。
1.Jenkins Pipeline用のプロジェクトpatientui-pipelineを作成します。
$ oc new-project patientui-pipeline
2.「oc new-app」コマンドを使用してテンプレートからJenkins Pipelineと患者用UIのアプリケーションを作成します。
$ oc new-app -f patientui-pipeline.yaml
3.Podの起動を確認すると多少時間はかかりますが、しばらくするとJenkinsが起動しているのがわかります。
$ oc get pod NAME READY STATUS RESTARTS AGE jenkins-1-bqnn2 1/1 Running 0 6m
4.ビルド設定(BuildConfig)を確認します。
$ oc get bc NAME TYPE FROM LATEST patientui Source Git 0 patientui-pipeline JenkinsPipeline 0
BuildConfigにはJenkins Pipelineのpatientui-pipelineと患者用UIのpatientuiができています。
5.ImageStreamには、まだコンテナイメージがないため、TAGSは空白です。
$ oc get is -n health-testing NAME DOCKER REPO TAGS UPDATED patientui docker-registry.default.svc:5000/health-pipeline/patientui
6.開発環境で動作しているJenkinsが検証環境、本番環境のような他のプロジェクトに対して実行できるようにするには、検証環境、本番環境の編集(edit)ロールをpatientui-pipelineプロジェクトのjenkinsサービスアカウントに追加します。
- 検証環境(health-testing) $ oc policy add-role-to-user \ edit system:serviceaccount:patientui-pipeline:jenkins -n health-testing role "edit" added: "system:serviceaccount:patientui-pipeline:jenkins" - 本番環境(health-production) $ oc policy add-role-to-user \ edit system:serviceaccount:patientui-pipeline:jenkins -n health-production role "edit" added: "system:serviceaccount:patientui-pipeline:jenkins"
7.検証環境、本番環境から開発環境のImageStreamのイメージを参照できるようにsystem:image-pullerロールをdefault(全てのPod)サービスアカウントに追加します。
- 検証環境(health-testing) $ oc policy add-role-to-user \ system:image-puller system:serviceaccount:health-testing:default \ -n patientui-pipeline role "system:image-puller" added: "system:serviceaccount:health-testing:default" - 本番環境(health-production) $ oc policy add-role-to-user \ system:image-puller system:serviceaccount:health-production:default \ -n patientui-pipeline role "system:image-puller" added: "system:serviceaccount:health-production:default"
8.GitHubでnode-s2i-openshiftリポジトリの/site/public/login.htmlファイルに[ patient pipeline test-1] という文字列を追加して、Pipelineビルドが終わった後に各環境間で同じ文字列が表示されるか確認したいと思います。
9.Pipelineビルドを開始します。
$ oc start-build patientui-pipeline build.build.openshift.io/patientui-pipeline-1 started
10.ビルドの進行状況を確認するとpatientui-pipeline-1がRunning(進行中)であることが確認できます。
$ oc get build NAME TYPE FROM STATUS STARTED DURATION patientui-pipeline-1 JenkinsPipeline Running 5 seconds ago
11.OpenShiftのWebコンソールにログインし、patientui-pipelineプロジェクトのjenkins-ephemeralアプリケーションのFQDNをクリックします。
12.Jenkins Pipelineビルドは、「Build Image」ステージで、コンテナイメージをビルドしています。
上図の「Stage View」では各ステージの処理の内容についてはわかりませんが、各ステージのコンソールの出力は記録されていて参照することができます。「Build Image」ステージのログを確認するとGitHubリポジトリからソースコードを取得してビルドを行い、patientui:latestにpushしていることがわかります。
13.Jenkins Pipelineのジョブが終了すると各ステージの処理結果と各ステージの所要時間が表示されます。
14.次に、Jenkins Pipelineビルドによって作成されたImageStreamのタグを確認します。「oc get is」コマンドでそれぞれImageStreamを確認するとバージョン(2.0-1)でタグ付けされていることがわかります。
- 開発環境 $ oc get is -n patientui-pipeline NAME DOCKER REPO TAG UPDATED patientu (省略):5000/patientui-pipeline/patientu 2.0-1,latest About a minute ago - 検証環境 $ oc get is -n health-testing NAME DOCKER REPO TAG UPDATED patientu (省略):5000/patientui-testing/patientu 2.0-1,latest,1.0-2 + 1 more.. About a minute ago - 本番環境 $ oc get is -n health-production NAME DOCKER REPO TAG UPDATED patientu (省略):5000/patientui-production/patientu 2.0-1,latest,1.0-2 + 1 more.. About a minute ago
15.最後に各環境にデプロイしたアプリケーションを確認すると文字列の変更が全ての環境で反映していることがわかります。
新しいJenkins Pipelineビルドを始めるためには、開発担当のアプリケーションのソースコードの変更がリポジトリにプッシュした後、Jenkins Pipelineビルドを開始するだけです。ビルドにWebhookトリガーを有効にすれば、この手順も必要ないですね。
$ oc start-build patientui-pipeline build "patientui-pipeline-2" started
これで開発環境のアプリケーションのビルド、検証環境と本番環境のアプリケーションのデプロイをJenkins Pipelineビルドを使って展開することができました。Jenkinsを使って全てのステップを自動化、可視化することで、アプリケーションのリリースが短縮できますし、オペレーションミスなど意図しない変更が発生しなくなります。
みなさんがそれぞれの要件で配信プロセスを作るときは前述のOpenShift 4.2の製品ドキュメント 5.4. PIPELINE ビルドに加えてOpenShiftの開発者ガイド「2.3. 環境全体におけるアプリケーションのプロモート」も参考にするといいと思います。
自分のパソコンで今回の手順を試すことができるようにQiitaに「OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた(4)」を投稿しました。是非お試しください。
IBM CloudのマネージドサービスであるRed Hat OpenShift on IBM Cloudは、ブラウザ操作で簡単に短時間で、シングル構成から耐障害性のある複数のデータセンターによるマルチゾーン構成までOpenShiftクラスターを入手することができます。これまで、自分で構築するのが難しかった、インフラ担当がいなかったなど、障壁のあった企業にとっては朗報ですね。Red Hat OpenShiftは、Kubernetesを含むOpenShiftのコンポーメント全てがサポート対象であることが最大の利点だと思います。(Kubernetesはソフトウェアなのでバグは必ず発生します。)さらに今回の記事で紹介しましたがDevOpsやCI/CD(継続的インテグレーション/継続的デリバリー)を始めるための必要なコンポーネントが標準で用意されていて、OpenShiftの製品ドキュメントにユースケースが用意されているので、そのまま乗っかる形でDevOpsやCI/CDが始められるのが素晴らしいと思います。
OpenShiftの学習としてはExample HealthのOpenShiftによるJava EEアプリケーションのモダナイゼーション以外にもCode Patterns記事が用意されているので、ぜひ試されるといい経験になると思います。OpenShiftの製品ドキュメントの開発者ガイドも参考になると思います。また、IBM Developer DojoではOpenShift(Minishift)のハンズオンセミナーを定期的に開始しています。(2019年12月時点)自分で始めるのが難しい方は、そこで、サポートを受けながら自分のパソコンにOpenShift(Minishift)をインストールして始めることができるのでいい機会だと思います。
最後になりますが、お読みいただいた方へ
これまで3回の記事にお付き合いいただきまして、本当にありがとうございました。
私のこれまでの経験に基づいて書き綴ってみましたが、みなさんにとって何か一つでも参考になれば嬉しく思います。
ありがとうございました。
Copyright © ITmedia, Inc. All Rights Reserved.
提供:日本アイ・ビー・エム株式会社
アイティメディア営業企画/制作:@IT 編集部/掲載内容有効期限:2020年1月7日
本イベントでは、DojoのコンテンツをWebinar形式でオンラインで実施いたします。