連載 [第4回] :
  Red Hat OpenShiftの全貌

Projectとアプリケーションデプロイ

2019年1月18日(金)
長野 修
連載4回目となる今回は、OpenShiftにおけるProjectの解説、イメージのビルドやデプロイについて学びます。

本稿では下記の筋立てでOpenShiftを使った開発者向けのトピックを提供します。

  • Projectとは
  • ビルド済みのイメージを使う:CaaSとしての利用
    • Docker Hubのイメージの利用
      • セキュリティを緩める回避策
    • Docker Hubのイメージの利用2
      • Podのスケールアウト
      • どんなリソースができたか
      • oc runコマンドの別の使い方
    • ローカルのイメージの利用
      • Minishiftでの内部レジストリへのプッシュ
    • イメージのインポートとImageStream
    • OpenShiftでのDockerビルド
    • OpenShiftが提供するイメージの利用
  • イメージを自分で作成する:PaaSとしての利用
    • S2Iビルドとは
    • プログラムのソースコードの用意
    • JavaのS2Iビルド
    • インクリメンタルビルドの有効化
    • S2Iビルドのカスタマイズ
    • チェーンビルド
    • ビルドのトリガーについて

CDK(Minishift)を含むOpenShiftクラスタへログインが可能で、ocコマンドをインストール済みであることを想定しています。お使いのシェルにあわせて、下記のコマンドを実行してコマンドの補完機能を有効にしておくことをお勧めします。

リスト1:前準備として、コマンド補完機能を有効にしておく

$ source <(oc completion bash)

Projectとは

Project(混乱がない限り、カタカナ表記も用います)とは、OpenShiftクラスタにおける作業の単位です。ちょうど自分のマシンで何か作業をするときにまずディレクトリを作るように、OpenShiftでもまずProjectを作成し、そこですべての作業を行います。

ocコマンドでクラスタにログインした直後は、自分のProjectが何もない状態か、もしくはクラスタの管理者により作成された何らかのProject内にいる状態になっています。ログイン後に表示されたメッセージをよく見てみるか、oc statusまたはoc projectコマンドを実行して、現在のProjectが何かを確認してみて下さい。

Projectは気軽に新規作成できます。本稿の説明を何もない空のProjectから始めるためにも、「my-testproject」という名前で作ってみましょう。

リスト2:Projectの作成

$ oc new-project my-testproject

Projectの名前は、そのOpenShiftクラスタ内で一意である必要があります。これは、Projectの実体がKubernetesのNamespaceであるための制約です。Minishiftのような一人で独占できるOpenShiftクラスタ環境であれば問題ありませんが、共用の環境を使っている場合は「my-」の部分にユーザ名を適用するなどして、一意性を確保して下さい。

OpenShiftでは、さまざまな場面でこのProject名の一意性を利用しています。

例えば、Dockerのイメージ名が下記のルールで決められているのは、皆さんご存知のはずです。

リスト3:Dockerのイメージ名のルール

<registry>/<owner>/<repository>:<tag>

具体的には、Docker Hubにある公式のNginxの最新イメージは下記の名前で取得できます。

リスト4:Nginxの最新イメージを指定するには

docker.io/library/nginx:latest

実は、すべてのOpenShiftクラスタは統合されたDockerレジストリを内部に持っており、それが「<registry>」の部分になり、「<owner>」の部分にはProject名が使われるのです。

OpenShiftでは既存のイメージを使用するだけでなく、自分で作成することもできます。その作成されたイメージはOpenShift内のレジストリ(本稿では「内部レジストリ」と呼ぶことにします)に保存され、その名前の一意性を確保するために、Project名が一意であることを利用しています。

Projectにはこのように、他のユーザと作業空間を分けたり、作成されるイメージ名の一部になったりと、名前空間としての役割を持ちます。他にもユーザが使用可能なメモリやCPUなどのリソースをProject単位で制限したり、他のユーザに自分のProjectを見せたり編集させたりする権利を明示的に与える等、様々な役割があります。

ビルド済みのイメージを使う:CaaSとしての利用

Docker Hubには様々なイメージが公開されており、dockerコマンドが使える環境であれば手軽にそれらを試すことができます。例えば先にも触れたNginxのイメージをDockerで使うには、下記のように実行します。なお、イメージ名には「nginx」とだけ指定する短縮形を用いています。

リスト5:NginxのイメージをDockerで使用する

$ docker run -d -p 8080:80 nginx
5828ea67fc7ca11a3c1e454e56f9f12550c84b3e7fe00f4acbdb3b20e0d63437
$ curl http://localhost:8080/
(...)
<h1>Welcome to nginx!</h1>
(...)

そして不要になったら「docker rm -f 5828ea」で消すだけです。

OpenShiftでも、Dockerと同じくらい簡単に既存のイメージを利用でき、CaaS(Container as a Service)としての側面を持っています。ただし注意点もありますので、具体例に沿って見ていきましょう。

Docker Hubのイメージの利用

OpenShiftで既存のDockerイメージを指定してコンテナを起動するには、oc runコマンドを用います。これはKubernetesにあるkubectl runコマンドと同じです。

リスト6:oc runコマンドでNginxを起動

$ oc run nginx --port=80 --expose --image=nginx

何が起きたかを確認するために、Project内のすべてのリソースを表示させるoc get allを実行してみましょう。

リスト7:oc get allの実行結果

$ oc get all
NAME                READY     STATUS             RESTARTS   AGE
pod/nginx-1-6mdql   0/1       CrashLoopBackOff   3          1m

NAME                            DESIRED   CURRENT   READY     AGE
replicationcontroller/nginx-1   1         1         0         1m

NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/nginx   ClusterIP   172.30.131.239   <none>        80/TCP    1m

NAME                                       REVISION   DESIRED   CURRENT   TRIGGERED BY
deploymentconfig.apps.openshift.io/nginx   1          1         1         config

oc runを実行しただけなのに、何やら多くのリソースができています。そして、「pod/nginx-1-6mdql」が肝心のコンテナを含むリソースですが、「CrashLoopBackOff」というおかしな状態になっています。

実際、Nginxのコンテナの起動に失敗しているのです。oc logsコマンドを対象のPodに対して実行してログを見れば、何が起きているのか分ります。

リスト8:oc logsコマンド

$ oc logs pod/nginx-1-6mdql
2018/12/16 04:36:59 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in
/etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2018/12/16 04:36:59 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)

「実行ユーザの変更ができない」という警告([warn])の他、「Permission denied」でディレクトリの作成に失敗しています。これは、OpenShiftが通常ユーザでコンテナを起動しようとしている一方で、Nginxのイメージがroot権限を持つスーパーユーザでの実行を想定して作られているために起きているエラーです。

このように、Docker公式イメージのように広く使われているものですら、root権限を要求するものがあります。言うまでもなく、スーパーユーザでのプロセスの実行は好ましくありません。サーバのように長期間動作するものであれば、なおさらです。このセキュリティの問題をよく認識したうえで、その回避策をまず紹介します。

セキュリティを緩める回避策

回避策として、OpenShiftクラスタの管理者にお願いして、Podを実行するアカウントである「default」に、rootを含む任意のユーザを使う許可「anyuid」を与えてもらうというのがあります。

次に示すコマンドは、クラスタの管理権限を持つユーザでログインし直して実行するが必要あります。

リスト9:anyuidを与える

# oc adm policy add-scc-to-user anyuid -z default

もしくは、自分がクラスタ管理者でもあるなら、--asオプションを用いてこのコマンドに限って別のユーザで実行することも可能です。

リスト10:自分が管理者の場合は以下のとおり

$ oc adm policy add-scc-to-user anyuid -z default --as=system:admin

OpenShiftでは、コンテナに適当なUIDを割り当てて実行しようとします。上記のNginxの例では、実際の実行ユーザはDockerfileで指定されたrootユーザ(UID=0)ではなく、「1000500000」のような適当に採番されたUIDの一般ユーザになっています。そのため実行時にエラーとなっていました。

「anyuid」はSCC(Security Context Constraint)の一種で、コンテナの実行ユーザを実行しようとしているイメージのDockerfileのUSERインストラクションで指定されているUIDにするものです。特にUSERインストラクションの指定がない場合はrootが使われますが、「anyuid」を指定することで、それも許可されます。

そして「default」はSA(Service Account)の一つで、Projectごとに自動で設けられ、そのProject内で動作するPodがデフォルトで使用するアカウントになります。正式名称はプロジェクト名を含んだ「system:serviceaccount:my-testproject:default」ですが、同じプロジェクト内で上記のコマンドを実行する分には「-z default」のように省略した記述が使えます。

実は、Minishiftの環境では、このanyuidがすべてのログイン済みユーザにデフォルトで与えられるようになっています(oc adm policy add-scc-to-user anyuid system:authenticatedと同等のコマンドが実行済みの状態で起動する)。これはMinishiftでOpenShiftに入門する人向けの特別な措置で、既存のroot権限を必要とする多くのイメージを、とりあえず使えるようにするためのものです。

このようにanyuidを許可することは、極めて大きなセキュリティ上のリスクにもなり得ます。どうしても必要な場合は、Minishiftのように広範なユーザ(system:authenticate)に対して許可するのではなく、「-z default」のようにプロジェクトごとに制限されたService Accountに対して許可するようにしましょう。

理想的には、root権限を必要としないような、適切に設計されたイメージのみを使うべきです。Red Hat Container Catalogでは、RHELをベースにした安全なイメージが多数用意されており、製品版のOpenShiftやCDKからはデフォルトで利用可能になっています。

Docker Hubのイメージの利用2

さて、回避策としてのanyuid権限を与えた上で、改めてDocker HubのNginxイメージをOpenShiftで使ってみましょう。

まず前の実行でできたものを削除します。oc runコマンドでできたリソースには「run=<runコマンドに与えた名前>」のラベルが付きますので、ラベルを指定して削除を実行します。

リスト11:前に作成したイメージの削除

$ oc delete all -l run=nginx

そして改めてoc runコマンドを実行します。

リスト12:oc runコマンドを再度実行

$ oc run nginx --port=80 --expose --image=nginx
$ oc get all
NAME                READY     STATUS    RESTARTS   AGE
pod/nginx-1-xrd78   1/1       Running   0          5m

NAME                            DESIRED   CURRENT   READY     AGE
replicationcontroller/nginx-1   1         1         1         5m

NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/nginx   ClusterIP   172.30.150.229   <none>        80/TCP    5m

NAME                                       REVISION   DESIRED   CURRENT   TRIGGERED BY
deploymentconfig.apps.openshift.io/nginx   1          1         1         config

今度はPodのステータスが「Running」になっているはずです。

しかし、このままではOpenShift内で動作するPodからしかアクセスできません。Podの外部からアクセスするには、Routeを作成します。これはロードバランサやリバースプロキシのような役割を持つリソースです。

リスト13:外部からアクセスできるようにRouteを作成

$ oc expose svc nginx

できたRouteがどういうURLを公開したかをoc get routeコマンドで確認し、実際にアクセスしてみます。

リスト14:作成したRouteの確認

$ oc get route
NAME      HOST/PORT                                    PATH      SERVICES   PORT      TERMINATION   WILDCARD
nginx     nginx-my-testproject.192.168.42.254.nip.io             nginx      80                      None
$ curl http://nginx-my-testproject.192.168.42.254.nip.io/
(...)
<h1>Welcome to nginx!</h1>
(...)

正しくHTMLページが返されているのが分ります。

Podのスケールアウト

OpenShiftおよびそれが内部で使用しているKubernetesが、コンテナのオーケストレーションシステムと呼ばれる所以の一端を見てみましょう。まずはoc scaleコマンドでPodの数を3つに増やしてみます。

リスト15:Podを増やす

$ oc scale dc nginx --replicas=3
$ oc get pod -w
(Podの変化をモニタする。Ctrl-Cで終了)

Podがすべて出そろったら、ターミナルを3つ開き、それぞれで「oc logs -f <Pod名>」を実行します。このNginxイメージは、アクセスログを標準出力に表示するようになっています。ブラウザやcurlコマンドでアクセスするたびに、いずれかのPodにアクセスログが出力され、リクエストがロードバランスされるのが分かるはずです。このように複数のPodをまとめ上げて動作させることが簡単にできます。

どんなリソースができたか

oc get allコマンドで出てきたリソースの種類に何があるかを簡単に説明します。

リソースの種類

リソース短縮名説明
DeploymentConfig dcReplicationControllerを通じて使用するイメージのバージョンを管理する
ReplicationControllerrcPodが指定された台数(レプリカ数)だけ動くように管理する
Pod poコンテナを動かす。一つのPodに複数のコンテナを配置することも可能
Servicesvc複数のPodを代表するクラスタ内でのみ有効なIPアドレスを提供する
RouteServiceに対してクラスタ外部からアクセス可能なURLを提供する

初めのうちは、「DeploymentConfig、ReplicationController、Podの3階層のリソース群でコンテナオーケストレーションを実現している」と理解しておけば十分です。

なお歴史的理由により、OpenShiftではKubernetesとは少し異なるリソースを使っています。お互いにほとんど同じ役割を持つため、違いを気にせねばならないケースは多くはありませんが、対応表を載せておきます。

OpenShiftとKubernetesのリソースの対応

OpenShiftKubernetes
DeploymentConfigDeployment
ReplicationControllerReplicaSet
RouteIngress

DeploymentなどKubernetesのリソースも通常どおり使用できますので、Kubernetesで使っていたマニフェストファイルをそのまま移行することも可能です。

oc runコマンドの別の使い方

docker runコマンドではコンテナが一つできるだけなのに、oc runコマンドではPodだけでなくDeploymentConfigなどもできて、大掛かりな仕掛けになってしまいました。指定したイメージを使ったPodを一つだけ実行させるといったシンプルな使い方はできないのでしょうか?

実は、--restart=Neverオプションを付けることでそれも可能です。Docker HubのFedoraイメージを対話的に使ってみることで確認してみましょう。

リスト16:Podを一つだけ実行

$ oc run fedora -it --image=fedora --restart=Never --command -- bash
If you don't see a command prompt, try pressing enter.
[root@fedora /]# curl http://nginx/
(...)
<h1>Welcome to nginx!</h1>
(...)
[root@fedora /]# exit

起動したbashの中では特に、「curl http://nginx/」としてサービス名「nginx」を使ってPodにアクセスしています。Routeを使わずにPodにアクセスするには、このように同じOpenShiftのネットワーク環境で動くPodが必要です。

--restartオプションは省略すると「Always」が指定されたとみなされ、その場合はPodを常に起動しておこうと試みるため、DeploymentConfigによる管理が行われるのです。これはNginxのようなサーバプログラムには適切ですが、単にコマンドを実行したいといった場合には大げさです。そこで「Never」を指定してやることで、一回きりのPodが必要であることを伝え、余計なリソースを作成しないようにできます。ちなみに、--restartに指定可能なオプションには他に「OnFailure」がありますが、これを指定した場合はJobというリソースがPodを管理するようになります。

ローカルのイメージの利用

ここまでの例では、Docker Hubでインターネットに公開されているイメージを使ってきました。ここからは、まだどこのレジストリにもプッシュされておらず、自分のローカルマシンにしかないイメージをOpenShiftの内部レジストリにプッシュして、それを使ってみます。

あらかじめ、適当なHTMLファイルをコピーしてある「mynginx」というイメージが、ローカルのDockerにあるとして、これを内部レジストリにプッシュします。

まずは正しい内部レジストリ名とProject名を使って、タグを付けておきます。

リスト17:タグの付与

$ docker tag mynginx docker-registry-default.example.com/my-testproject/mynginx:latest

上記の例では内部レジストリ名は「docker-registry-default.example.com」になっています。お使いの環境でどうなっているかは、クラスタ管理者にお問い合わせ下さい。内部レジストリは「docker-registry」という名前で「default」プロジェクトに存在しますので、「default」プロジェクトのview権限があるアカウントで下記のコマンドを実行して確認することもできます。

リスト18:内部レジストリ名の確認

$ oc get route -n default --as=system:admin

正しい名前でタグを付け終わったら、内部レジストリにログインし、docker pushコマンドを実行します。内部レジストリはOpenShiftと統合されているため、認証情報にocコマンドの結果を用いることができます。

リスト19:docker pushコマンドの実行

$ docker login -u $(oc whoami) -p $(oc whoami -t) docker-registry-default.example.com
$ docker push docker-registry-default.example.com/my-testproject/mynginx:latest

これで、指定したイメージ名がOpenShiftのプロジェクトからも使えるようになりました。これまでの例と同様に、oc runコマンドでそのイメージが使えます。加えて、my-testproject内には「mynginx」という名前のImageStream(短縮名はis)もできているはずです。ImageStreamは、より多機能であるoc new-appというコマンドで使うことができます。詳細は後ほど説明しますが、ここでは簡単に使い方だけ見てみます。

リスト20:oc runより多機能なoc new-app

$ oc get is
NAME      DOCKER REPO                                                  TAGS      UPDATED
mynginx   docker-registry-default.example.com/my-testproject/mynginx   latest    13 minutes ago
$ oc new-app mynginx
$ oc expose svc mynginx
$ oc get route mynginx
NAME      HOST/PORT                                      PATH      SERVICES   PORT      TERMINATION   WILDCARD
mynginx   mynginx-my-testproject.192.168.42.254.nip.io             mynginx    80-tcp                  None
$ curl http://mynginx-my-testproject.192.168.42.254.nip.io/

上記のように、oc new-appに続いてoc expose svcでRouteを作成し、oc get routeでできたRouteを確認してcurlでアクセスするというパターンはこれからも頻出しますので、覚えておくとよいでしょう。

Minishiftでの内部レジストリへのプッシュ

Minishiftの環境では内部レジストリは公開されておらず、そのままではアクセスする手段がありません。しかし、Minishiftの仮想マシン内で動くDockerデーモンと直接通信するための裏技が用意されていますので、それを使います。

まず、プッシュしたいイメージをローカルファイルとして保存しておきます。次にdockerコマンドのための環境変数を定義するMinishiftの裏技を実行して、dockerコマンドの接続先をMinishift内部のものに変更します。このコマンド以降は、ローカルのDockerデーモンにはアクセスできません。あらかじめdocker saveコマンドを実行するのはそのためです。その後docker loadコマンドで新しいDockerデーモンにイメージをロードします。

リスト21:Minishift環境での内部レジストリの扱い

$ docker save mynginx > mynginx.tar
$ source <(minishift docker-env)
$ docker load -i mynginx.tar

Dockerデーモンの切り替えを先に行っておき、その後「mynginx」イメージのビルドを行うという方法でも同じ効果を達成できます。

後は通常の場合と同じです。Minishiftの内部レジストリ名は、デフォルトでは「172.30.1.1:5000」となりますが、minishift openshift registryコマンドでプログマラブルに取得することもできます。

リスト22:Minishift環境で内部レジストリ名を取得

$ docker tag mynginx $(minishift openshift registry)/my-testproject/mynginx:latest
$ docker login -u $(oc whoami) -p $(oc whoami -t) $(minishift openshift registry)
$ docker push $(minishift openshift registry)/my-testproject/mynginx:latest

正しくImageStreamができているか確認してみましょう。

リスト23:ImageStreamができていることを確認

$ oc get is
NAME      DOCKER REPO                              TAGS      UPDATED
mynginx   172.30.1.1:5000/my-testproject/mynginx   latest    54 seconds ago

イメージのインポートとImageStream

先の例では、Docker HubのNginxイメージを、Kubernetesと同様のoc runコマンドによって実行してみました。一方、ローカルにあったmynginxイメージを内部リポジトリにプッシュしてから使う例では、できたImageStreamをoc new-appコマンドで利用しました。

実はoc new-appコマンドに直接Dockerイメージを指定して実行することも可能です。ただしImageStreamの名前と誤解されないように、レジストリ名を含んだフルネームを指定する必要があります。

リスト24:oc new-appコマンドでDockerイメージを指定

$ oc new-app docker.io/library/nginx

oc runコマンドを使った場合との違いは、ImageStreamも追加で作られる点です。

リスト25:ImageStreamも作られている

$ oc get is
NAME      DOCKER REPO                            TAGS      UPDATED
nginx     172.30.1.1:5000/my-testproject/nginx   latest    About a minute ago

ImageStreamはOpenShiftに固有のリソースで、複数のImageStreamTag(短縮名istag)を内部に持っています。そしてImageStreamTagは、ある特定のDockerイメージに対する間接参照を提供します。タグ名はデフォルトで「latest」になりますので、できたImageStreamTagの詳細を見るには次のように実行します。

リスト26:ImageStreamTagの詳細を確認

$ oc describe istag nginx:latest

DeploymentConfigなどのOpenShiftの他のリソースからイメージを指定する場合は、実際にはこのImageStreamTagが用いられていることが多いです。Gitなどのバージョン管理システムにおけるブランチ名のように、普段は固定の名前を用いて、それが指す具体的なイメージの方を変えていくといった使い方ができます。また、ImageStreamTagが指すDockerイメージの変更をOpenShiftが検知して、それをトリガーに自動でデプロイを開始するといった機能も担っています。

あるDockerイメージを指すImageStreamを、自分の好きな名前で作ることも可能です。今度はDocker HubのApache httpdのイメージを例に使ってみましょう。

リスト27:ImageStreamの名前を指定

$ oc import-image myhttpd --from=docker.io/library/httpd --confirm
(インポートしたイメージに関する説明)
$ oc get is
NAME      DOCKER REPO                              TAGS      UPDATED
myhttpd   172.30.1.1:5000/my-testproject/myhttpd   latest    About a minute ago

実行後にインポートしたイメージに関する説明が表示されますが、これはoc describe istag myhttpd:latestで表示されるものと同じです。上記の例ではインポート時にタグ名を省略したので、デフォルトの「latest」が使われました。インポートできたら、以降の流れは前と同じです。

リスト28:インポート後の作業は以前と一緒

$ oc new-app myhttpd
$ oc expose svc myhttpd
$ oc get route myhttpd
NAME      HOST/PORT                                      PATH      SERVICES   PORT      TERMINATION   WILDCARD
myhttpd   myhttpd-my-testproject.192.168.42.254.nip.io             myhttpd    80-tcp                  None
$ curl http://myhttpd-my-testproject.192.168.42.254.nip.io/
<html><body><h1>It works!</h1></body></html>

OpenShiftでのDockerビルド

これまでにインターネットに公開されているイメージを使う方法と、ローカルにある既存のイメージを使う方法を見てきました。次はDockerを(直接的には)使わず、OpenShiftだけでDockerイメージのビルドを行ってみます。

適当な作業用のディレクトリに、下記の内容でDockerfileとindex.htmlの2つのファイルがあるとします。

リスト29:Dockerイメージビルドの下準備

$ ls -l
total 8
-rw-r--r--. 1 onagano onagano 49 Dec 11 11:45 Dockerfile
-rw-r--r--. 1 onagano onagano 82 Dec 11 11:47 index.html
$ cat Dockerfile
FROM nginx
COPY index.html /usr/share/nginx/html
$ cat index.html
<head>
    <title>Test Page</title>
</head>
<body>
    <h1>Test Page</h1>
</body>

ローカルにあるファイルをCOPYインストラクションで利用しています。OpenShiftでこうしたDockerビルドを行うには、「バイナリービルド」と呼ばれる手順を実行します。具体的にはまずoc new-buildコマンドでBuildConfigを作成し、次にoc start-buildコマンドでビルドを開始するという、2段階の操作が必要です。

リスト30:バイナリービルドの2段階の操作

$ oc new-build --name=mynginx --strategy=docker --binary
$ oc start-build mynginx --from-dir=. --follow
(...)
Push successful

上記のコマンドのオプションについて説明しておきましょう。oc new-buildコマンドの--strategyオプションで、Dockerビルドであることを明示しています。そして--binaryオプションで、これがローカルファイルを使用するバイナリービルドであることを指示しています。そしてそのローカルファイルがOpenShiftクラスタからも見えるように、oc start-buildコマンドの--from-dirオプションで場所を指定しています。

ビルドの成果物として「mynginx」という名前のImageStreamができますので、あとはそれをoc new-app mynginxのように実行するだけです。

OpenShiftが提供するイメージの利用

Nginxイメージを例に、Docker Hubにあるイメージでもroot権限を要求する危険なものも含まれていること、およびそれを回避するanyuidのSCC付与も望ましくないことを先に説明しました。ではどのようなイメージを使えばいいのでしょうか?

答えは「セキュリティを考慮して作られたイメージ(およびそれを参照するImageStream)」です。そのようなイメージは「openshift」プロジェクト内に用意されていますので、そこから目ぼしいものを選んで使えばよいのです。「openshift」プロジェクトは、デフォルトですべてのユーザにview権限が与えられていますので、-nオプションで名前空間を指定してoc getコマンドやoc describeコマンドで詳しく調べることができます。

リスト31:イメージを検索し詳細を表示

$ oc get is -n openshift # ImageStreamの一覧を表示させる
$ oc describe is nginx -n openshift # ImageStream "nginx"の詳細を表示させる

上記のコマンドでは、「nginx」と名付けられたImageStreamの詳細も表示させています。その詳細をよく見てみると、「1.12」や「1.10」のように複数のImageStreamTagがあるのが分ります。個別のImageStreamについて調べたければ、「nginx:1.12」のようにコロンの後にタグ名を付けて、詳細を確認できます。ImageStreamTagの詳細の出力量はかなり多いですが、ここでは「Docker Labels」のセクションに表示されている下記の2つのラベルに注目してみます。

リスト32:注目すべきラベル

io.openshift.tags=builder,nginx,rh-nginx112<br/>
io.openshift.s2i.scripts-url=image:///usr/libexec/s2i

これらのラベルは、このイメージが普通とは異なるS2I(Source to Image)のビルダーイメージであることを表明しています。そしてこうしたビルダーイメージは、oc runコマンドでの利用は想定されておらず、代わりにoc new-appコマンドでのS2Iビルドを想定して作られているのです。

S2Iビルドの説明はのちのセクションに譲るとして、ここでは使い方を見てみましょう。oc new-appコマンドの主なオプションとして、「~」を挟んだ下記の書式が用いられます。

リスト33:S2Iビルドに必要なソースコードを指定する書式

<S2Iのビルダーイメージ名>~<ソースコードの場所>

今回の例では 「<S2Iのビルダーイメージ名>」が「nginx」、「<ソースコードの場所>」が「https://github.com/sclorg/nginx-container」です。NginxはWebサーバですので、この場合ソースコードはHTMLファイル群を意味します。このURLで示されたGitリポジトリを見てみると、ディレクトリ「examples/1.12/test-app」内にテストにちょうど良いHTMLファイル群が見つかります。--context-dirオプションでそのディレクトリを指定して、このS2Iビルドのソースとして使うよう指示しています。

まとめると下記のような実行例になります。

リスト34:S2Iビルドからcurlまでの流れ

$ oc new-app --name=mysite nginx~https://github.com/sclorg/nginx-container --context-dir=examples/1.12/test-app
$ oc expose svc mysite
$ oc get route mysite
NAME      HOST/PORT                                     PATH      SERVICES   PORT       TERMINATION   WILDCARD
mysite    mysite-my-testproject.192.168.42.254.nip.io             mysite     8080-tcp                 None
$ curl http://mysite-my-testproject.192.168.42.254.nip.io/
<html>
<head>
        <title>Test NGINX passed</title>
</head>
<body>
<h1>NGINX is working</h1>
</body>
</html>

以上の操作だけでNginxに指定したHTMLファイル群が入ったDockerイメージができ、それを参照するImageStreamもできるのです。

GitHubで別のHTMLファイル群を見つけたなら、それをソースにしてS2Iビルドを行ってみるのもいいでしょう。しかしS2Iビルドの本領は、プログラミング言語のビルダーイメージを使った際に発揮されます。次のセクションでは本格的なプログラミング言語のS2Iビルドの例としてJavaのビルダーイメージを使ってみます。

本稿では詳しく触れることはできませんが、openshiftプロジェクトにはImageStreamだけでなく多数のTemplateも登録されています。Templateは、複数のリソースの定義をパラメタ化して、あるソフトウェアスタックを一気に作り出すことができるリソースです。「oc get template -n openshift」を実行し、興味のあるリソースについて「oc describe template」コマンド実行して詳細を確認してみて下さい。openshiftプロジェクトにある多数のImageStreamやTemplateは、「oc new-app -S」コマンドで検索をかけることも可能です。

なお、これまでの作業で作成されたリソースは、下記のコマンドでプロジェクトごと消してかまいません。

リスト35:次に備えてプロジェクトを削除

$ oc delete project my-testproject
レッドハット株式会社

サービス事業統括本部 第1コンサルティング部 コンサルタント
金融とITの共通分野でキャリアを築くことを決意し、転職を繰り返して米系大手投資銀行でポータル開発の職にたどりつくも、リーマンショックであえなく撃沈。今はIT一本に絞って、JBossミドルウェアやOpenShiftの案件をデリバリしている。何らかのOSSプロジェクトにもっと具体的な貢献をしたいと思いつつ、めまぐるしく変わっていく流行りの技術に流され気味。いずれブロックチェーンに手を出す気がしている。

連載バックナンバー

クラウド技術解説
第5回

OpenShift:アプリケーションの構成と運用

2019/3/28
連載5回目となる今回は、OpenShiftでデプロイしたアプリケーションの運用に関するトピックを紹介する。
クラウド技術解説
第4回

Projectとアプリケーションデプロイ

2019/1/18
連載4回目となる今回は、OpenShiftにおけるProjectの解説、イメージのビルドやデプロイについて学びます。
クラウド技術解説
第3回

開発環境の準備とOpenShiftへのアクセス

2018/12/20
連載3回目となる今回は、OpenShiftの学習と開発のための環境を準備する手順を紹介いたします。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています