めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

OpenShift OriginによるDockerイメージ管理(4)〜S2Iによるイメージビルド

はじめに

enakai00.hatenablog.com

上記の記事では、GitHubで公開したDockerfileとその他の関連ファイルを用いてDockerイメージを作成しました。一方、Dockerfile単体でビルドできるイメージの場合、DockerfileだけをGitHubにアップロードするのは少し大げさです。このような際は、ビルド設定(BuildConfig)にDockerfileの内容をインラインで記述してしまうことも可能です。

また、OpenShiftでは、Dockerfileを使用にせずに、独自に用意したスクリプトを用いてイメージの作成を自動化する「Source to Image(S2I)」という機能も利用できます。ここでは、これらの手法でイメージを作成する例を紹介します。

はじめに準備として、例によって、プロジェクトを作成して、CentOS7のベースイメージをイメージストリームに登録しておきます。

# oc login -u enakai
# oc delete project project01
# oc new-project project01 --description="Project to learn S2I image build" --display-name="Learning S2I Image Development"

# docker pull centos:7
# docker login -u enakai -e enakai@example.com -p $(oc whoami -t) registry.oso.example.com
# docker tag docker.io/centos:7 registry.oso.example.com/project01/centos7:latest
# docker push registry.oso.example.com/project01/centos7:latest

Dcokerfileをインラインで記述する例

この後で、node.jsを用いたアプリケーションイメージをビルドするので、その準備として、CentOS7にnodejs関連のパッケージを追加したイメージを作成して、イメージストリーム「nodejs-base」に登録します。次の設定ファイルで、イメージストリームとビルド設定をまとめて登録します。

apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: ImageStream
  metadata:
    name: nodejs-base
  
- apiVersion: v1
  kind: BuildConfig
  metadata:
    name: nodejs-base
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: nodejs-base:latest
    source:
      dockerfile: |
        FROM centos:7
        MAINTAINER E.Nakai
        RUN yum -y install epel-release; yum -y install nodejs npm
        RUN useradd node -u 9999
        USER 9999
      type: Dockerfile
    strategy:
      dockerStrategy:
        from:
          kind: ImageStreamTag
          name: centos7:latest
      type: Docker
    triggers:
    - imageChange: {}
      type: ImageChange

ビルド設定「nodejs-base」を見ると、「source.type」に「Dockerfile」が指定されています。これは、「source.dockerfile」にインラインで記載されたDockerfileを使用することを意味します。その他の設定は、これまでの説明と同様です。実際に設定を登録すると、次のようになります。

# oc create -f nodejs-base_bc.yml 
imagestream "nodejs-base" created
buildconfig "nodejs-base" created

# oc get is
NAME          DOCKER REPO                               TAGS      UPDATED
centos7       172.30.84.64:5000/project01/centos7       latest    5 minutes ago
nodejs-base   172.30.84.64:5000/project01/nodejs-base  

# oc describe bc nodejs-base
Name:           nodejs-base
Created:        About a minute ago
Labels:         <none>
Latest Version: Never built
Strategy:       Docker
Source Type:    Dockerfile
Dockerfile:
  FROM centos:7
  MAINTAINER E.Nakai
  RUN yum -y install epel-release; yum -y install nodejs npm
  RUN useradd node -u 9999
  USER 9999
  
From Image:     ImageStreamTag centos7:latest
Output to:      ImageStreamTag nodejs-base:latest
Triggered by:   ImageChange

ビルド設定の中にDockerfileの内容が含まれていることが分かります。ここでは、ユーザー「node」を作成して、「USER」をUIDで指定している点に注意してください。これは、S2Iのベースイメージとして必要な設定となります。S2Iのビルドプロセスは、このようにUIDで指定された一般ユーザーによって実行することが前提となるためです。

このまましばらく待つと、「triggers:」で指定したトリガーによって、ビルドが開始されます。もしくは、次のコマンドで明示的にビルドを開始します。

# oc start-build nodejs-base
nodejs-base-1

# oc get build
NAME             TYPE      FROM         STATUS     STARTED         DURATION
nodejs-base-1    Docker    Dockerfile   Running    6 seconds ago   6s
# oc logs -f build/nodejs-base-1
Step 0 : FROM 172.30.84.64:5000/project01/centos7@sha256:b04ac745db2b0c65049667b26df41226b9875a139719ac0f3b41fed57b00c3c9
 ---> 60e65a8e4030
...
Successfully built 63142468eb03
I0103 02:12:06.393278       1 docker.go:86] Pushing image 172.30.84.64:5000/project01/nodejs-base:latest ...
I0103 02:12:52.004238       1 docker.go:90] Push successful

# oc describe is nodejs-base
Name:                   nodejs-base
Created:                3 minutes ago
Labels:                 <none>
Annotations:            openshift.io/image.dockerRepositoryCheck=2016-01-03T08:09:22Z
Docker Pull Spec:       172.30.84.64:5000/project01/nodejs-base

Tag     Spec            Created                 PullSpec                                                                                                        Image
latest  <pushed>        About a minute ago      172.30.84.64:5000/project01/nodejs-base@sha256:ed8a1c57bee0ea10a4be3fc84bc4cd11fc87b28b3caa949e6af1bc76b5f02132 

S2Iによるイメージ作成の例

S2Iを使用する際は、アプリケーションのビルドに必要なソースファイル一式をGitHubで公開しておきます。この時、「.sti/bin」以下に、「asssemble」、および、「run」というスクリプトを含めます。これらは、それぞれ、アプリケーションのビルド、および、実行に用いられます。ここでは、例として、下記で公開しているEtherpad-Liteのソースを利用します。

enakai00/etherpad-lite

assemble、および、runの内容は下記の通りで、「OpenShift OriginによるDockerイメージ管理(3)〜Dockerfileからイメージを作成する際のお作法」で説明したお作法に従って、アプリケーションの導入・実行を行ないます。本来はバックエンドのMySQLを必要としますが、ここでは簡単のためにテスト用の組み込みDB(dirtydb)を使用する設定としています。(MySQLのコンテナと連携する方法は、次回に解説します。)なお、GitHubから取得したコンテンツは、デフォルトで「/tmp/src」に配置されるので、assembleでは、その前提でのビルド処理を行っています。

.sti/bin/assemble

#!/bin/bash

APP_ROOT=/home/node
SRC=/tmp/src

cp -a $SRC/* $APP_ROOT/
cd $APP_ROOT
sh bin/installDeps.sh
cp -f settings.json.template settings.json
chmod og+rwx $APP_ROOT
chmod -R og+w $APP_ROOT

.sti/bin/run

#!/bin/bash

APP_ROOT=/home/node
cd $APP_ROOT
/usr/bin/node node_modules/ep_etherpad-lite/node/server.js

そして、これを用いて、S2Iを実行するビルド設定は、次のとおりです。先ほどと同様に、作成したイメージを出力するイメージストリームもあわせて定義しています。

etherpad-lite_bc.yml

apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: ImageStream
  metadata:
    name: etherpad-lite

- apiVersion: v1
  kind: BuildConfig
  metadata:
    name: etherpad-lite
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: etherpad-lite:latest
    source:
      git:
        uri: https://github.com/enakai00/etherpad-lite.git
        ref: openshift_1.5.7
      type: Git
    strategy:
      sourceStrategy:
        from:
          kind: ImageStreamTag
          name: nodejs-base:latest
      type: Source
    triggers:
    - imageChange: {}
      type: ImageChange

「spec.strategy.type」の「Source」が、S2Iによるビルドの指定になります。また、「spec.source.git」に、GitHubのURLと使用するブランチ(この例では「openshift_1.5.7」)を指定しています。

# oc create -f etherpad-lite_bc.yml 
imagestream "etherpad-lite" created
buildconfig "etherpad-lite" created

# oc get is
NAME            DOCKER REPO                                 TAGS      UPDATED
centos7         172.30.84.64:5000/project01/centos7         latest    28 minutes ago
etherpad-lite   172.30.84.64:5000/project01/etherpad-lite             
nodejs-base     172.30.84.64:5000/project01/nodejs-base     latest    21 minutes ago

# oc describe bc etherpad-lite
Name:           etherpad-lite
Created:        27 seconds ago
Labels:         <none>
Latest Version: Never built
Strategy:       Source
Source Type:    Git
URL:            https://github.com/enakai00/etherpad-lite.git
Ref:            openshift_1.5.7
From Image:     ImageStreamTag nodejs-base:latest
Output to:      ImageStreamTag etherpad-lite:latest
Triggered by:   ImageChange

ビルドを開始します。ログを見ると、ベースイメージからコンテナを起動した後、GitHubからソースを取得して、「assemble」スクリプトを実行していることが分かります。

# oc start-build etherpad-lite
etherpad-lite-1

# oc get build
NAME              TYPE      FROM                  STATUS     STARTED          DURATION
etherpad-lite-1   Source    Git@openshift_1.5.7   Running    1 seconds ago    1s
nodejs-base-1     Docker    Dockerfile            Complete   26 minutes ago   40s

# oc logs -f build/etherpad-lite-1
I0103 08:37:00.110401       1 sti.go:163] The value of ALLOWED_UIDS is [1-]
I0103 08:37:00.116206       1 docker.go:230] Pulling image 172.30.84.64:5000/project01/nodejs-base@sha256:ed8a1c57bee0ea10a4be3fc84bc4cd11fc87b28b3caa949e6af1bc76b5f02132
...
I0103 08:39:45.620174       1 sti.go:217] Pushing 172.30.84.64:5000/project01/etherpad-lite:latest image ...
I0103 08:40:29.900013       1 sti.go:233] Successfully pushed 172.30.84.64:5000/project01/etherpad-lite:latest

# oc describe is etherpad-lite
Name:                   etherpad-lite
Created:                5 minutes ago
Labels:                 <none>
Annotations:            openshift.io/image.dockerRepositoryCheck=2016-01-03T08:35:50Z
Docker Pull Spec:       172.30.84.64:5000/project01/etherpad-lite

Tag     Spec            Created                 PullSpec                                                                                                                Image
latest  <pushed>        About a minute ago      172.30.84.64:5000/project01/etherpad-lite@sha256:05c4600b8abec75a85c32baed153c0023cc0cbc7ab0250a3f14ce5d66962ed46       

アプリケーションの実行

それでは、完成したアプリケーションイメージを実行してみましょう。デプロイ設定(DeploymentConfig)、サービス(Service)、ルーティング(Route)をまとめて一気に設定してしまいます。

etherpad-lite_deploy.yml

apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: DeploymentConfig
  metadata:
    name: etherpad-lite
  spec:
    template:
      metadata:
        labels:
          name: etherpad-lite
      spec:
        containers:
        - name: etherpad-lite-latest
          image: etherpad-lite:latest
          ports:
          - containerPort: 9001
            protocol: TCP
    replicas: 1
    selector:
      name: etherpad-lite
    triggers:
    - type: ImageChange
      imageChangeParams:
        automatic: true
        containerNames:
        - etherpad-lite-latest
        from:
          kind: ImageStreamTag
          name: etherpad-lite:latest
    - type: ConfigChange

- apiVersion: v1
  kind: Service
  metadata:
    name: etherpad-lite
  spec:
    ports:
    - name: 9001-tcp
      protocol: TCP
      port: 9001
      targetPort: 9001
    selector:
      deploymentconfig: etherpad-lite

- apiVersion: v1
  kind: Route
  metadata:
    name: etherpad-lite-route
  spec:
    host: eplite.project01.oso.example.com
    to:
      kind: Service
      name: etherpad-lite
# oc create -f etherpad-lite_deploy.yml 
deploymentconfig "etherpad-lite" created
service "etherpad-lite" created
route "etherpad-lite-route" created

# oc describe dc etherpad-lite
Name:           etherpad-lite
Created:        About a minute ago
Labels:         <none>
Latest Version: 1
Triggers:       Image(etherpad-lite@latest, auto=true), Config
Strategy:       Rolling
Template:
  Selector:     name=etherpad-lite
  Replicas:     1
  Containers:
  NAME                  IMAGE                                                                                                                   ENV
  etherpad-lite-latest  172.30.84.64:5000/project01/etherpad-lite@sha256:05c4600b8abec75a85c32baed153c0023cc0cbc7ab0250a3f14ce5d66962ed46       
Deployment #1 (latest):
        Name:           etherpad-lite-1
        Created:        about a minute ago
        Status:         Complete
        Replicas:       1 current / 1 desired
        Selector:       deployment=etherpad-lite-1,deploymentconfig=etherpad-lite,name=etherpad-lite
        Labels:         openshift.io/deployment-config.name=etherpad-lite
        Pods Status:    1 Running / 0 Waiting / 0 Succeeded / 0 Failed

# oc get pod
NAME                    READY     STATUS      RESTARTS   AGE
etherpad-lite-1-build   0/1       Completed   0          8m
etherpad-lite-1-x3elu   1/1       Running     0          31s
nodejs-base-1-build     0/1       Completed   0          34m

# oc get service
NAME            CLUSTER_IP      EXTERNAL_IP   PORT(S)    SELECTOR                         AGE
etherpad-lite   172.30.14.201   <none>        9001/TCP   deploymentconfig=etherpad-lite   45s

# oc get route
NAME                  HOST/PORT                          PATH      SERVICE         LABELS    INSECURE POLICY   TLS TERMINATION
etherpad-lite-route   eplite.project01.oso.example.com             etherpad-lite                               

これで、「http://eplite.project01.oso.example.com」にアクセスすると、Etherpadが利用できるようになっています。