Helidonで作ったマイクロサービスをPrometheus Operatorでサクッとモニタリング

Helidonとは

HelidonはマイクロサービスなWeb APIを実装することを想定したJavaフレームワークです。以下のような特徴があります。

  • 割と軽い実装で、パフォーマンスに優れる
  • MicroProfileの実装の一つ
  • PrometheusやZipkinの形式のメトリック/トレーシングの情報を簡単に取得できる

f:id:charlier_shoe:20190207113902j:plain

このエントリーでやること

Helidonで作ったマイクロサービスをPrometheus Operatorでサクッとモニタリングしてみます。だいたい以下のような流れになります。

  1. Kubernetesクラスター上に、PrometheusとPrometheus Operatorをデプロイする
  2. Helidonでアプリを作成し、Kubernetesクラスターにデプロイする
  3. Prometheusでアプリのアクセスカウンターをモニタリングする

では順に行きたいと思います。

1. Kubernetesクラスター上に、PrometheusとPrometheus Operatorをデプロイする

CRDやらなんやらをKubernetesクラスターに作ることになるので、kubectlコマンドを実行するアカウントに必要な権限をつけておきます。 今回はKubernetesの環境として、OKE(Oracle Container Engine for Kubernetes)を利用します。この場合、以下のようなコマンドを実行します(cluster-adminロールをつけて楽しちゃってます)。

kubectl create clusterrolebinding [Cluster Role Bindingオブジェクトの名前] --clusterrole=cluster-admin --user=[kubectlの実行アカウントのOCID]

詳細はOKEのドキュメントを参照ください。

次に、適当なディレクトリにPrometheus Operatorをcloneします。

git clone -b v0.28.0 https://github.com/coreos/prometheus-operator.git
cd prometheus-operator

諸々をクラスターにデプロイします。 (2019/02/06時点でkube-prometheusはExperimentalだそうなので、今後同じ方法が使えるかは未知数です)

kubectl apply -f contrib/kube-prometheus/manifests/

Podが上がりきったのを確認したら、Prometheusのダッシュボードにアクセスします。PrometheusにのダッシュボードにつながるServiceはClusterIPで作られているので、port forwardを使います。

kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090

上のコマンドを実行したら、ブラウザでhttp://localhost:9090/にアクセスします。以下のような感じでダッシュボードが表示されればOKです。

f:id:charlier_shoe:20190207013510p:plain

2. Helidonでアプリを作成し、Kubernetesクラスターにデプロイする

HelidonのアプリはクイックスタートにあるHello World的なアプリを使います。

まず、以下のコマンドを実行します。

mvn archetype:generate -DinteractiveMode=false \
    -DarchetypeGroupId=io.helidon.archetypes \
    -DarchetypeArtifactId=helidon-quickstart-se \
    -DarchetypeVersion=0.11.0 \
    -DgroupId=io.helidon.examples \
    -DartifactId=quickstart-se \
    -Dpackage=io.helidon.examples.quickstart.se
cd quickstart-se

これでHelidonのプロジェクトの雛形が作成されますが、この雛形にはすでにHello World的なAPIが実装されています。

この雛形に、カスタムメトリックとしてアクセスカウンターを追加してみます。

やり方はHelidonのドキュメントのMetrics supportに従えばOKですが、quickstartを使っている場合、必要な手順は一箇所だけ、GreetingServiceにアクセスカウンターを書き足す作業です。

vim src/main/java/io/helidon/examples/quickstart/se/GreetService.java

以下、diff形式で差分を記します。行頭に + が書かれているところを追記すればOKです。

@@ -25,6 +25,10 @@
 import io.helidon.webserver.ServerResponse;
 import io.helidon.webserver.Service;
 
+import io.helidon.metrics.RegistryFactory;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+
 /**
  * A simple service to greet you. Examples:
  *
@@ -42,6 +46,10 @@
 
 public class GreetService implements Service {
 
+    private final MetricRegistry registry = RegistryFactory.getRegistryFactory().get()
+        .getRegistry(MetricRegistry.Type.APPLICATION); 
+    private final Counter accessCtr = registry.counter("accessctr"); 
+
     /**
      * The config value for the key {@code greeting}.
      */
@@ -58,6 +66,7 @@
     @Override
     public void update(Routing.Rules rules) {
         rules
+            .any(this::countAccess)
             .get("/", this::getDefaultMessageHandler)
             .get("/{name}", this::getMessageHandler)
             .put("/greeting/{greeting}", this::updateGreetingHandler);
@@ -108,4 +117,9 @@
         response.send(returnObject);
     }
 
+    private void countAccess(ServerRequest request, ServerResponse response) {
+            accessCtr.inc(); 
+            request.next();
+    }
+
 }

Kubernetesにデプロイするためのmanifestファイルの雛形もあります。 後の手順でアプリをコンテナ化しますが、このときのイメージ名に合うように、manifestで指定するイメージ名を修正しておきます。

vim src/main/k8s/app.yaml

イメージ名をしている箇所で、元のイメージ名の頭に "[Docker Hubのアカウント名]/" を追記します。以下はhhiroshellというアカウント名の場合です。

@@ -43,7 +43,7 @@
     spec:
       containers:
       - name: ${project.artifactId}
-        image: ${project.artifactId}
+        image: hhiroshell/${project.artifactId}
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 8080

コードの編集が終わったら、アプリケーションをビルドしてローカルで実行してみます。まずはビルドから。

mvn package
[INFO] Scanning for projects...
...(中略)...
[INFO]
[INFO] --- maven-jar-plugin:2.5:jar (default-jar) @ quickstart-se ---
[INFO] Building jar: /mnt/c/Users/hhiroshell/Development/devsumi/quickstart-se/target/quickstart-se.jar [INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  34.004 s
[INFO] Finished at: 2019-02-06T14:14:55Z
[INFO] ------------------------------------------------------------------------

上記の様に BUILD SUCCESS で終わっていればOKです。次に、アプリを起動します。

java -jar target/quickstart-se.jar

何回かgreetingのAPIにアクセスして、アクセスカウンターをカウントアップさせておきます。

curl http://localhost:8080/greet

Helidonは、Prometheusからメトリックを取得するためのEndpointをデフォルトで持っています。ですので、直接 /metrics/ というパスにアクセスするとメトリックを取得できます。新たにExporterを用意する必要はありません。

先程追加したアクセスカウンターは、application:accessctr という名前でメトリックを提供しています。エンドポイントにアクセスして、このアクセスカウンターの値を見てみます。

curl -s -H 'Accept: text/plain' -X GET http://localhost:8080/metrics/ | grep accessctr
# TYPE application:accessctr counter
# HELP application:accessctr null
application:accessctr 5

この様になれば、仕込んでおいたアクセスカウンターのメトリックが取得できていることになります。Prometheusの形式で値が返ってきていることが分かります。

それでは、このアプリをKubernetesにデプロイします。雛形からDockerfileやKubernetesのmanifestが生成済みなので、それを利用していきます。

まずはコンテナのビルド。

docker build -t [Docker Hubのアカウント名]/quickstart-se target

具体的には、例えばこのようなコマンドになります。

docker build -t hhiroshell/quickstart-se target

次にコンテナレジストリにプッシュ。Docker Hubを使っているので、ログインが求められたらDocker Hubのユーザー名とパスワードを入力してください。

docker push [Docker Hubのアカウント名]/quickstart-se

具体的には、例えばこのようなコマンドになります。

docker push hhiroshell/quickstart-se

続いて、kubernetesにデプロイします。

kubectl apply -f target/app.yaml

雛形から生成したmanifestだと、NodePortタイプのServiceが作られている状態です。クラスター上のアプリにアクセスするため、まずはNodeのIPアドレスと、Serviceが公開されているPort番号を確認します。

kubectl get nodes -o wide
NAME            STATUS   ROLES   AGE   VERSION   INTERNAL-IP   EXTERNAL-IP     OS-IMAGE                  KERNEL-VERSION                   CONTAINER-RUNTIME
132.145.27.98   Ready    node    2h    v1.11.5   10.0.10.2     132.145.27.98   Oracle Linux Server 7.5   4.14.35-1818.2.1.el7uek.x86_64   docker://18.3.1

この結果から、EXTERNAL-IP の値を使います(Nodeが複数表示される場合どのNodeでもOK)。

次にPort番号です。

kubectl get service quickstart-se
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
quickstart-se   NodePort   10.96.255.64   <none>        8080:31621/TCP   7m

PORT(S)の : の右側にある値を使います。上の例では31621です。

それでは、Kubernetesクラスター上のアプリケーションにアクセスしてみます。

curl "http://[上で確認したIP]:[上で確認したPort番号]/greet"

何度かアクセスを繰り返して、アクセスカウンターの値を増やしておいてください。

これでHelidonのアプリのビルドとデプロイが完了しました。

3. Prometheusでアプリのアクセスカウンターをモニタリングする

Prometheus Operatorを使ってPrometheusを利用する場合、監視対象を追加するにはServiceMonitorというカスタムリソースを使います。これは、KubernetesのServiceがルーティング対象とするPodを、自動的にメトリック収集対象とするものです。

今回は、以下のようなカスタムリソースを、quickstart-service-monitor.yamlというファイル名で作成します。

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: quickstart-service-monitor
  labels:
    app: quickstart-se
spec:
  selector:
    matchLabels:
      app: quickstart-se
  endpoints:
  - port: http

このServiceMonitorは、Label Selectorとして app: quickstart-se と指定しています。こうすると、同じlabelを持ったServiceがルーティング対象とするPodに対して、メトリックを取得しに行くするように設定されます。

多くの場合、Prometheusがメトリックを取得しに行くEndpointにはExporterを用意しますが、HelidonはこのEndpointを予め持っており、そこから直接メトリックを得ることができます。

ではこのSerivceMonitorをクラスターに適用します。

kubectl apply -f quickstart-service-monitor.yaml

Prometeusの設定はこれだけでOKです。Operator便利ですね。

では、ブラウザでhttp://localhost:9090/にアクセスして、Prometheusのダッシュボードを表示します。

port-forwardが切れていたら、以下を実行してから上記のURLにアクセスします。

kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090

Expressionに"application:accessctr"と入力してExecuteをクリックすると、アクセスカウンターの値が取得できていることがわかります(メトリックが収集させるまでタイムラグがあるので、何も表示されなかった場合は少し時間を置いてください)。

f:id:charlier_shoe:20190207013607p:plain

次に、アプリをスケールアウトした場合も自動的に監視対象に追加されることを確認してみます。

まず、以下のコマンドでアプリのPod数を3に増やします。

kubectl scale deployment quickstart-se --replicas=3

アクセス数を追加でカウントアップさせるため、アプリへのアクセスを何度か行っておきます。
(↓を何度か実行)

curl "http://[上で確認したIP]:[上で確認したPort番号]/greet"

Prometheusのダッシュボードでアクセスカウンターのメトリックを観察すると、Pod毎に値が取得できていることがわかります。

f:id:charlier_shoe:20190207013632p:plain

まとめ

Helidonで作成したアプリのカスタムメトリックを、Prometheus Operatorを使ってモニタリングすることができました。

HelidonはExporterいらずでモニタリングできて便利です。また、Prometheus Operatorを使うとカスタムリソースを使うことで簡単にメトリックの収集対象を設定できます。

本エントリーは以上です!

Werckerのパイプライン内でDockerfileからコンテナをビルドする方法

Werckerはパイプラインの実行環境となっているコンテナからコンテナイメージを作るのがデフォルトの動きですが、なるべく軽量なコンテナにしたいなど、用途に最適化されたコンテナを作りたいという場合もあります。

そんなときは、コードリポジトリにDockerfileを入れておいて、それを使ってビルドすればOKです。

wercker.ymlの書き方は以下のような感じです。

box: alpine:3.6

build:
  steps:
    - internal/docker-build:
        name: build custom container.
        dockerfile: Dockerfile
        image-name: custom-container

    - internal/docker-push:
        name: push custom container.
        image-name: custom-container
        username: $REGISTRY_USERNAME
        password: $REGISTRY_PASSWORD
        repository: hhiroshell/custom-container
        tag: 1.0

internal/docker-build で所望のDockerのコンテキストでコンテナをビルドできます。 dockerfile: に設定しているのはDockerfileまでのパスです。パイプラインの実行中は、コードリポジトリのrootに当たるディレクトリがカレントになっています。上の例はコードリポジトリのrootの直下にDockerfileを置いておき、それを参照していることになります。

image-name:は後続のStepでイメージを操作したいときに、イメージを特定するための名前です。この例だと docker-push StepでビルドしたイメージをPushしています。

その他いろいろな設定が可能ですが、詳細は公式ドキュメントに詳しいです。

Oracle Cloud InfrastructureのCLIをvirtualenv環境内にインストールする

Oracle Cloud Infrastructure(以下、OCI)のCLIPythonで実装されています。Pythonのvirtualenvを使って、OCI CLI専用の環境を切ってインストールしておけば、Pythonにありがちな依存モジュールの問題に悩まされずに済みますので、このエントリーではその手順を書きます。1

ちなみに、本エントリーとは直接関係ありませんが、CLIの他にOCIのAnsibleモジュールも使いたい場合には、より一層virtualenvの利用をおすすめしたいです。OCIのAnsibleモジュールはOCIのPython SDKというものに依存しているのですが、自分の環境では依存モジュールの問題にはまって動かすまで苦労したので…。

前提条件

こんな環境でやりました。

手順

pipをインストール

sudo apt update
sudo apt install python3-pip

pipでvirtualenvをインストール

pip3 install virtualenv

OCI CLI用のvirtualenv環境を作成。virtualenvは新たにディレクトリを切って、その配下で依存パッケージが管理される仕組みです。ここでは、~/.pyenv_oci-cliという名前のディレクトリにしています。

python3 -m virtualenv ~/.pyenv_oci-cli --no-site-packages

上で作成したvirtualenvを有効化

source ~/.pyenv_oci-cli/bin/activate

pipでvirtualenv環境にOCI CLIをインストール

pip install oci-cli

動作確認。以下のコマンドでヘルプが表示されればOKです。

oci -h

新たにシェルを立ち上げたら、都度virtualenvの有効化を行う必要があります。頻繁にOCI CLIを使うのであれば、.bashrcとか.zshrcに該当コマンドを書いておくと良いかと思います。

source ~/.pyenv_oci-cli/bin/activate

OCI CLIのインストールはこれで完了です。CLIの環境設定の手順はvirtualenvを使っていてもいなくても同じなので、「Oracle Cloud Infrastructure CLIを設定してみた」などを参考にして実施してください。


  1. virtualenvを使わない標準的なインストール手順は、こちらこちらを参照ください。

Ubuntu 18.04 bionicにOpenJDK 11をインストールする

2018/12/27現在、Ubuntu 18.04でaptでOpenJDKをインストールするとjdk10がインストールされるようになっています。1

いろいろと対処法はあるようなのですが、せっかくなので本家のOpenJDKを落として手動でインストールしとこうということで、その手順を残しておきます。

手順

OpenJDKのダウンロードサイトに行って、ビルド済みのアーカイブを取得するためのURLを確認します。

Ubuntu 18.04の場合は、Linux/x64のURLを確認して適当に控えて置きます。

以下、順次以下のコマンドを実行します。URLやファイル名などは本稿執筆時点のものなので、作業を行う時点のものを確認して適宜置き換えてください。

アーカイブのダウンロード

wget https://downlo8ad.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz -O ./openjdk-11.0.1_linux-x64_bin.tar.gz

解凍

sudo mkdir /usr/lib/jvm
sudo tar xfvz ./openjdk-11.0.1_linux-x64_bin.tar.gz --directory /usr/lib/jvm

お掃除

rm openjdk-11.0.1_linux-x64_bin.tar.gz

コマンドにシンボリックリンクを貼っておく

javajavacくらいはやっておくと便利かと。

sudo ln -s /usr/lib/jvm/jdk-11.0.1/bin/java /usr/bin/java
sudo ln -s /usr/lib/jvm/jdk-11.0.1/bin/javac /usr/bin/javac

動作確認

こんな結果になればおk

java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

以上です。

OKE、OCIRを使うときに権限制御するための設定まとめ

このエントリーはOracle Cloud アドベントカレンダーその2の22日目です。

今回はOracleが提供するコンテナ関連のクラウドサービスである、OKE、OCIRを使う上での、準備に当たる作業の話を書きたいと思います。

これらを使うには、Policyと呼ばれるアクセス権限の設定を予めしておく必要があります。 このエントリーでは、それら必要な権限周りの設定を整理したいと思います(他のエントリーではそのエントリーで必要なものだけ書いているので)。

管理者権限を打ち込めばすぐに使えるようにはなりますが、ちゃんと権限を分けたいときにはこの情報を算用してください。

OKEを使うために必要なポリシー

注: in tenancyin compartment [コンパートメント名]のようにすると、権限の及ぶ範囲をコンパート名に絞る事ができます。

  • OKEのPaaSに与える権限OKEを使つときは必須

    • Statement:
      • Allow service OKE to manage all-resources in tenancy
    • 説明:
      • OKEのPaaSに権限を与えるための特殊なポリシー。OKEを使うときはこれを必ず作る。これがないと始まらない
  • OKEクラスターとNode Poolを操作する権限

    • Statement:
      • Allow group [グループ名] to manage cluster-family in tenancy
      • Allow group [グループ名] to inspect vcns in tenancy
      • Allow group [グループ名] to inspect subnets in tenancy
    • 説明:
      • OKEのクラスターとNode Poodを操作する権限(3つセット)。3つのうち下のの2つは、クラスターが依存する下回りのネットワークを参照するためのもの。
      • このセットには下回りのネットワークをいじる権限は含まれない(依存するネットワークは作成済みの前提)
  • OKEクラスターとNode Poolを操作する権限 + ネットワークの操作権限

    • Statement:
      • Allow group [グループ名] to manage cluster-family in tenancy
      • Allow group [グループ名] to manage virtual-network-family in tenancy
    • 説明:
      • OKEをネットワークも含めて作ったり操作したいときに必要な権限。2つ目の方は下回りのネットワークを操作するためのもの
      • OKE作成のダイアログでquick clusterを使うときにはこの権限が必要
  • OKEクラスターを参照する権限

    • Statement:
      • Allow group [グループ名] to inspect clusters in tenancy
    • 説明:
  • OKEクラスターのNode Poolを操作する権限

    • Statement:
      • Allow group [グループ名] to use cluster-node-pools in tenancy
    • 説明:
      • 作成済みのOKEクラスターのNode Poolを追加、削除、アップデート(構成変更など)する権限
  • OKEクラスターへの操作の監査情報を参照する権限

    • Statement:
      • Allow group [グループ名] to read cluster-work-requests in tenancy
    • 説明:
      • OKEクラスターへの操作の監査情報を参照する権限

OCIRを使うために必要なポリシー

以下は全てを網羅したものではありませんが、ほとんどのケースはこれらがあれば大丈夫かと思います。

  • リポジトリの閲覧権限

    • Statement:
      • Allow group [グループ名] to inspect repos in tenancy
    • 説明:
  • イメージの取得権限(全てのリポジトリ

    • Statement:
      • Allow group [グループ名] to read repos in tenancy
    • 説明:
  • イメージの取得権限(リポジトリを限定)

    • Statement:
      • Allow group [グループ名] to read repos in tenancy where all { target.repo.name=/[リポジトリ名]/ }
    • 説明:
      • OCIRの指定されたリポジトリのイメージをpullする権限。/example-app*/のように正規表現を使うこともできる模様
  • イメージの登録権限(全てのリポジトリ

    • Statement:
      • Allow group [グループ名] to use repos in tenancy
    • 説明:
  • イメージの登録権限(リポジトリが存在しない場合に新たに作る権限も追加)

    • Statement:
      • Allow group [グループ名] to manage repos in tenancy where ANY {request.permission = 'REPOSITORY_CREATE', request.permission = 'REPOSITORY_UPDATE'}
    • 説明:
  • OCIRへのフルアクセス

    • Statement:
      • Allow group [グループ名] to manage repos in tenancy
    • 説明:

Oracle Container Engine for KubernetesでLoadBlancerタイプのServiceを使う

このエントリーはOracle Cloud アドベントカレンダーその2の21日目です。

今回は、OKE(Oracle Container Engine for Kubernetes)で作ったKubernetesクラスターでLoadBalancerタイプのServiceを使う手順を紹介します。

0. 前提条件

  • OKEのクラスターをプロビジョング済みであること。手順はこちらをご参照ください。

1. 手順

ほとんどのマネージドKubernetesサービスは、自身のクラウド環境で提供されているロードバランサーのサービスと連携してServiceオブジェクトを作成する機能を提供しており、OKEも同様です。

1.1. まずはデフォルト設定で

まずは、my-nginx.yamlというファイル名で以下のような内容のファイルを作成します。

apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

これはなんの変哲もない、nginxのコンテナを公開するだけのmanifestファイルです。

これをOKEクラスターに適用してみます。

kubectl apply -f my-nginx.yaml

10-20秒程度おいてから以下のコマンドを実行し、Serviceオブジェクトの内容を確認してみます。

k get svc
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
kubernetes     ClusterIP      10.96.0.1       <none>           443/TCP        15m
my-nginx-svc   LoadBalancer   10.96.122.251   129.213.78.183   80:32250/TCP   30s

my-nginx-svcというServiceが129.213.78.183というIPアドレスで公開されていることがわかります(IPアドレスは環境や実行の度に変わります)。

ブラウザでこのアドレスhttp://129.213.78.183/アクセスすると、OKEクラスターで動いているnginxからの応答を得ることができます。

f:id:charlier_shoe:20181221162747p:plain

Oracle Cloud Infrastructureのコンソールでロードバランサーの方を確認してみると、ランダムに生成されたと思しき名前でロードバランサーが作られていることがわかります。

f:id:charlier_shoe:20181221162759p:plain

IPアドレスは先程のアドレス一致します。また、シェイプは[100]Mbpsになっていると思います。

Oracle Cloud Infrastructureでは400[Mbps]と8000[Mbps]も提供しています。これらを使いたい場合には、Serviceオブジェクトの記述にannotationを追加します。

  • 400[Mbps]
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
  annotations:                                                  <--ココ
    service.beta.kubernetes.io/oci-load-balancer-shape: 400Mbps <--ココ
...(以下略)...
  • 8000[Mbps]
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
  annotations:                                                   <--ココ
    service.beta.kubernetes.io/oci-load-balancer-shape: 8000Mbps <--ココ
...(以下略)...

例えば400[Mbpx]でやってみます。ファイルを変更後、以下のコマンドを実行します。

kubectl delete -f my-nginx.yaml
kubectl create -f my-nginx.yaml

今度は400[Mbps]のロードバランサーができました!(ロードバランサーの作り直しになるので、IPアドレスも変わっています)

f:id:charlier_shoe:20181221162831p:plain

本エントリーでご紹介する内容は以上です。

シェイプを変更する以外にもSSLを終端するように設定したりすることも可能です。詳しくは公式のドキュメントを参照してください。

WerckerでオリジナルのStepを導入する

このエントリーはOracle Cloudアドベントカレンダーの14日目です。

WerckerはOracleが提供するCI/CDサービスです。元々はオランダ発のスタートアップだったWercker社が提供していたサービスでしたが、2017年にOracleが買収し、その後継続してサービスが提供されています。

Werckerは全てのCI/CDパイプラインをコンテナで実行する仕組みになっており、ユーザーが任意のコンテナをパイプラインに組み込むことが可能です。 これにより、パイプラインで実行する処理内容を自由にカスタマイズできるようになっています。

このエントリーでは、簡単なサンプルを題材に、Werckerでオリジナルの処理をパイプラインに組み込む方法を書きたいと思います。

題材

Docker公式のWhalesayというコンテナを使って、クジラにセリフを喋らせる(標準出力に表示する)処理をパイプラインで実行してみます。

手順

では手順を書いていきます。

Stepを作る

Werckerのパイプラインで実行される処理は、Stepという最小単位で構成されています。Stepはおおよそシェルのコマンドを1回実行するのに相当する処理に当たります。

ここでは、Whalesayコンテナ上で実行する処理を定義するStepを作成します。

まず、Stepの作成に必要なファイルをホストするリポジトリGitHub上に用意しておきます。たとえば、wercker-step-whalesayなどの名前でリポジトリを作成します。

必要なファイルは以下の3つです。これらを作成して上記リポジトリにPushしていきます。

ファイル名 役割
run.sh Stepで実行する処理のエントリーポイントとなるスクリプト
step.yml Stepの仕様(名前や指定可能な変数など)を定義するymlファイル
wercker.yml Stepをビルドして、Werckerサービスに登録ときに利用される、ビルド定義ファイル

それぞれ、以下のような内容です。

run.sh
Step処理が実行されるときこのスクリプトがキックされます。中身はクジラに喋らせるコマンドを実行しているだけです。
$WERCKER_WHALESAY_MESSAGEは、Stepを使うときに指定した変数を環境変数から拾ってきています。

#!/bin/sh
cowsay $WERCKER_WHALESAY_MESSAGE

step.yml
ステップの仕様を定義します。名前はwhalesay、massageという変数を文字列で指定する、などといった内容が書いてあります。
指定した変数の値は、WERCKER<Step名><変数名>という形式の環境変数から取得できます。run.shでは、そうやってメッセージを拾っています。

name: whalesay 
version: 1.0.0
summary: whalesay
properties:
- name: message
  type: string
  required: true

wercker.yml
Stepの作成自体もWerckerのパイプラインで行うのですが、これはそのパイプラインの定義です。run.shのチェックとWerckerサービスへの登録を行います。
このパイプラインが正常に完了すれば、以降任意のパイプラインで利用可能なStepとして登録されます。

box: docker/whalesay

build:
  steps:
  - shellcheck:
      files: run.sh

publish:
  steps:
  - internal/publish-step:
      owner: hhiroshell
      # private: true

以上のファイルをリポジトリにPushしたら、Werckerでこのリポジトリに紐付いたApplicationsを作成してください。Applicationの作成は右上の"Add Application"から。基本デフォルトの設定でウィザードを流すだけなので、迷わないと思います。

f:id:charlier_shoe:20181217011249p:plain

次に、Workfrowタブでワークフローを作成します。Workflowタブを選択すると、デフォルトのBuildパイプラインがあるだけのフローが表示されています。

f:id:charlier_shoe:20181217011337p:plain

この画面の下の方にある"Add new pipeline"ボタンをクリックし、以下の設定でPipelineを作成します。

  • Name: publish
  • YML Pipeline name: publish
  • Hook type: Default

次にbuildパイプラインの右の[+]マークをクリックし、publishpパイプラインを追加します。"Execute Pipeline"でpublishを選択し、他の項目は全てデフォルトでOKです。

f:id:charlier_shoe:20181217011446p:plain

Runsタブを選択し画面下方のリンクからWorkflowを起動します。正常に終了したら、画面右上のアバターをクリックし、更にYour profileを選択します。Stepsの中にwhalesayが表示されていればStepの作成、登録は完了です。

f:id:charlier_shoe:20181217011509p:plain

whalesayステップの内容を開くと、以下のような説明が表示されます。

f:id:charlier_shoe:20181217011533p:plain

Stepを使う

それでは、作成したwhalesayステップを実際に使ってみます。新たなGitHubリポジトリを作成し、以下のファイルをPushしてください。

wercker.yml
デフォルトのpipelineであるbuildの中で、shalesayステップを呼び出しています。
変数messageの値をクジラが喋ってくれるはず。

build:
  box: docker/whalesay
  steps:
  - hhiroshell/whalesay@1.0.0:
      message: "hello whalesay !!"

先ほどと同様に、このリポジトリに紐付いたApplicationを作成します。今回はbuildパイプラインしかありませんので、ワークフローの編集は不要です。

最後にワークフローを実行してみます。

正常に終了したら、実行結果のbuildパイプラインに当たる部分をクリックし、その詳細情報にアクセスします。

f:id:charlier_shoe:20181217011550p:plain

whalesayというStepの部分を展開すると、そのStepの処理での標準出力の内容が表示されます。クジラが喋っていれば成功です。

f:id:charlier_shoe:20181217011604p:plain

まとめ

以上で、whalesayというコンテナをパイプラインに組み込んで、クジラに喋らせるコマンドを実行するStepを走らせることができました。

これと同じ要領で、任意のコンテナをパイプライン内で使うことが可能です。もちろん自作のコンテナを組み込んでStepとして実行することができますので、やろうと思えばほとんどどんなことでもできることになります。

以下は、TerraformをStepで実行してAWS環境の操作を行っている例です。ご参考までに、引用させていただきます。

TerraformとWerckerとAWS Organizationsで始めるステージング・開発環境構築

本エントリーは以上です。