2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

IBM Cloud で Argo workflow を動かす時の課題とOperatorによる対処法

Last updated at Posted at 2020-07-15

IBM Cloud Kubernetes サービス (通称:IKS)で、Aego Workflow を動作させる場合の注意点について挙げ、これらに対処しながら、Argo workflow を利用する方法について記述した。この情報は、執筆時点の情報であり、Argoプロジェクトは、インキュベーション段階にあるため、プロジェクトの成長と時間経過によって、ここに挙げた問題は解決されることを願う。

問題1 クラウドのPostgreSQLと接続できない

Argo workflow は、ジョブの実行状態を管理するために、PostgreSQL または MySQL を利用することになっている。クイックインストールでは、Kubernetesクラスタ上に PostgreSQL を起動する。しかも、永続ボリュームを使わず、コンテナ上にデータを保存している。そのため、停止と起動を実施すると、過去のデータを失ってしまう。

この問題を解決するために、クラウドのデータベースサービス PostgreSQL を利用したい。クラウドのデータベースサービスは、クラウド内から内部的に接続できるだけでなく、パブリックネットワークにエンドポイントを置いて、クラウド外からも利用できる。そのため、クライアント証明書を使用したTLS暗号化による接続が必須となっている。ところが、Argo workflow の データベース接続のコードでは、TLS証明書の設定が明確になっていない。 以下にソースコード(https://github.com/argoproj/argo/blob/master/persist/sqldb/sqldb.go) を添付した。インポートしているPostgreSQLのライブラリがTLS証明書をサポートしていれば、簡単に機能追加して、プルリクを挙げられそうな気がする。

persist/sqldb/sqldb.go抜粋
package sqldb

import (
	"fmt"
	"time"

	log "github.com/sirupsen/logrus"
	"k8s.io/client-go/kubernetes"
	"upper.io/db.v3/lib/sqlbuilder"
	"upper.io/db.v3/mysql"
	"upper.io/db.v3/postgresql"

<中略>
func CreatePostGresDBSession(kubectlConfig kubernetes.Interface, namespace string, cfg *config.PostgreSQLConfig, persistPool *config.ConnectionPool) (sqlbuilder.Database, string, error) {

	if cfg.TableName == "" {
		return nil, "", errors.InternalError("tableName is empty")
	}

	userNameByte, err := util.GetSecrets(kubectlConfig, namespace, cfg.UsernameSecret.Name, cfg.UsernameSecret.Key)
	if err != nil {
		return nil, "", err
	}
	passwordByte, err := util.GetSecrets(kubectlConfig, namespace, cfg.PasswordSecret.Name, cfg.PasswordSecret.Key)
	if err != nil {
		return nil, "", err
	}

	var settings = postgresql.ConnectionURL{
		User:     string(userNameByte),
		Password: string(passwordByte),
		Host:     cfg.Host + ":" + cfg.Port,
		Database: cfg.Database,
	}

	if cfg.SSL {
		if cfg.SSLMode != "" {
			options := map[string]string{
				"sslmode": cfg.SSLMode,
			}
			settings.Options = options
		}
	}

	session, err := postgresql.Open(settings)
	if err != nil {
		return nil, "", err
	}
<後略>

上記の理由から、現時点ではクラウドのPostgreSQLデータベースのサービスと接続できない。 OperatorHubには、PostgreSQLのオペレータが複数登録されているので、この中から品質の良いものを選択して使用するのが良さそうだ。

問題2 デフォルトのエクゼキューターでは動かない

現在のArgo workflow でのエクゼキューターとしては選択できるのは、Docker, kubelet, Kubernetes API (k8sapi), Porcess Namespace Shring (pns) であり、デフォルトは Docker になっている。しかし、Dockerをコンテナランタイムに使用しているクラウドは、もはや存在しない。残りから評価して選択する必要がある。利点と欠点を、アルゴプロジェクトのドキュメントに挙げてあるので、https://argoproj.github.io/argo/workflow-executors/ 参考にすると良い。

筆者が試したところ、Docker 以外のエクゼキューターに 変更することで問題が発生した。 GitHub の Issue generate artifact via script failed when mounted emptyDir #1667 (https://github.com/argoproj/argo/issues/1667 にも上がっているが、Openを継続している(2020/7/15)

オンプレミスのKubernetesクラスタでは、コンテナランタイムをDockerに切り替えて、Argo workflow を利用することが出来るが、クラウドのKubernetesサービスでは、利用者が自由に変更できないので、問題を許容する必要がある。

Dockerエンジンでも内部的にcontainerdを使用しているので、以下のように、UNIXソケットのアドレス設定を加えることで、コンテンを実行は可能であるが、結果をアウトプットする段階でエラーになる。

workflow-controller-configmap.yaml抜粋
apiVersion: v1
kind: ConfigMap
metadata:
  name: workflow-controller-configmap
data:
  artifactRepository: |
    archiveLogs: true
    s3:
      bucket: my-bucket
 <中略>
   containerRuntimeExecutor: docker
   dockerSockPath: /var/run/containerd/containerd.sock

以下のようにエクゼキューターを k8sapiにすることで、制約はあるものの利用できるようになる。

workflow-controller-configmap.yaml抜粋
   containerRuntimeExecutor: k8sapi

問題3 オブジェクトストレージのHMAC有効化された認証情報が必須

Argo workflow は、AWS S3、GCS, Minio がサンプルとして挙げられている(https://argoproj.github.io/argo/configure-artifact-repository/) 。もちろん、S3互換API を持つオブジェクト・ストレージへの接続も可能だ。IBM Cloud のオブジェクトストレージを使用する場合、認証情報を生成する際に詳細オプションから、HMAC資格情報(https://cloud.ibm.com/docs/cloud-object-storage/hmac?topic=cloud-object-storage-hmac&locale=ja) を有効化しておく必要がある。これによって、S3互換のアクセスキーとシークレットを生成するので、これをセットする。

以下にICOS(IBM Cloud Object Storage)を使用する際のワークフローコントローラーのコンフィグマップをあげる。

workflow-controller-configmap.yaml抜粋
apiVersion: v1
kind: ConfigMap
metadata:
  name: workflow-controller-configmap
data:
  artifactRepository: |
    archiveLogs: true
    s3:                                                                                          
      endpoint: s3.jp-tok.cloud-object-storage.appdomain.cloud                                   
      bucket: argo-workflow-artifacts                                                            
      accessKeySecret:                                                                           
        name: my-icos-cred                                                                       
        key: accesskey                                                                           
      secretKeySecret:                                                                           
        name: my-icos-cred                                                                       
        key: secretkey                                                                           
      insecure: true  

この例では、シークレット my-icos-cred に accesskey と secretkey の設定が必要となる。これは、HMACを有効化することで、cos_hmac_keys が生成される。access_key_id を accesskey、 seceretkey を secret_access_keyにそれぞれセットすることでアクセスできる。

{
  "apikey": "0viPHOY7LbLNa9eLftrtHPpTjoGv6hbLD1QalRXikliJ",
  "cos_hmac_keys": {
      "access_key_id": "347aa3a4b34344f8bc7c7cccdf856e4c",
      "secret_access_key": "gvurfb82712ad14e7a7915h763a6i87155d30a1234364f61"
  },
  "endpoints": "https://control.cloud-object-storage.test.cloud.ibm.com/v2/endpoints",
  "iam_apikey_description": "Auto generated apikey during resource-key operation for Instance - crn:v1:bluemix:public:cloud-object-storage:global:a/3ag0e9402tyfd5d29761c3e97696b71n:d6f74k03-6k4f-4a82-b165-697354o63903::",
  "iam_apikey_name": "auto-generated-apikey-f9274b63-ef0b-4b4e-a00b-b3bf9023f9dd",
  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/3ag0e9402tyfd5d29761c3e97696b71n::serviceid:ServiceId-540a4a41-7322-4fdd-a9e7-e0cb7ab760f9",
  "resource_instance_id": "crn:v1:bluemix:public:cloud-object-storage:global:a/3ag0e9402tyfd5d29761c3e97696b71n:d6f74k03-6k4f-4a82-b165-697354o63903::"
}

解決策 PostgreSQL オペレーターによるデプロイ

オペレーターHub の中から、Postgres-Operator (https://operatorhub.io/operator/postgres-operator)
を利用することにした。

はじめに、デフォルトの名前空間をdefaultにしてから、オペレーターをインストールする。

$ kubectl apply -k github.com/zalando/postgres-operator/manifests 
serviceaccount/postgres-operator created
clusterrole.rbac.authorization.k8s.io/postgres-operator created
clusterrole.rbac.authorization.k8s.io/postgres-pod created
clusterrolebinding.rbac.authorization.k8s.io/postgres-operator created
configmap/postgres-operator created
service/postgres-operator created
deployment.apps/postgres-operator created

$ kubectl get pod -l name=postgres-operator
NAME                                 READY   STATUS    RESTARTS   AGE
postgres-operator-85978df8cf-bxsnb   1/1     Running   0          14s

これで、Postgres-Operator の CRD が作成されるので、起動する PostgresSQL の設定を変更したい場合は利用できる。

$ kubectl get crd postgresqls.acid.zalan.do
NAME                        CREATED AT
postgresqls.acid.zalan.do   2020-07-15T00:11:20Z

$ kubectl get crd postgresqls.acid.zalan.do -o yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  creationTimestamp: "2020-07-15T00:11:20Z"
  generation: 1
  name: postgresqls.acid.zalan.do
  resourceVersion: "3142326"
  selfLink: /apis/apiextensions.k8s.io/v1/customresourcedefinitions/postgresqls.acid.zalan.do
  uid: b4aedc82-6949-4348-915a-aa35f217f481
<以下省略>

以下のYAMLを適用して、オペレーターに指示を与え、PostgreSQLを起動する。

postgresql-cluster.yaml
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: postgresql-cluster
spec:
  databases:
    argodb: argo
  numberOfInstances: 2
  postgresql:
    version: '11'
  teamId: POSTGRESQL
  users:
    argodb_user: []
    argo:
      - superuser
      - createdb
  volume:
    size: 5Gi
  patroni:
    pg_hba:
      - host all all 0.0.0.0/0 md5

このマニフェストを適用するだけで、オペレーターを起動してくれる。だいたい5分くらいで起動する。

$ kubectl apply -f postgresql-cluster.yaml

起動を確認するには次の方法が使える。二つのノードが異なるノードに配置されている。

maho:operator maho$ kubectl get pod -l application=spilo,cluster-name=postgresql-cluster -o wide
NAME                   READY   STATUS    RESTARTS   AGE     IP               NODE          postgresql-cluster-0   1/1     Running   0          5m38s   172.30.177.214   10.44.12.57
postgresql-cluster-1   1/1     Running   0          3m43s   172.30.195.98    10.44.10.23

オペレータで起動することで、PVCのマニフェストを書くことなく、永続ボリュームの確保も完了している。

$ kubectl get pvc 
NAME                          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                 AGE
pgdata-postgresql-cluster-0   Bound    pvc-9bf59b8d-75ab-46dc-be1c-8ba71b707f0b   10Gi       RWO            ibmc-vpc-block-10iops-tier   6m57s
pgdata-postgresql-cluster-1   Bound    pvc-7605eb6c-5fb3-4c66-9802-f23772bc48d6   10Gi       RWO            ibmc-vpc-block-10iops-tier   5m2s

postgresのパスワードは以下の方法で取得できる。

$ export PGPASSWORD=$(kubectl get secret postgres.postgresql-cluster.credentials -o 'jsonpath={.data.password}' | base64 -d)
$ echo $PGPASSWORD
6pTt0mhbA2OnwNTnabEVi3p8HLzwfaGe4qHpYdLM7FN1tzjwXpMEc9JJzwnoCBtf

このパスワードの値をシークレットに設定しておく。

postgresql-cred.yaml
apiVersion: v1
kind: Secret
metadata:
  name: argo-postgres-config  
  labels:
    app: argo
stringData:
  username: postgres
  password: 6pTt0mhbA2OnwNTnabEVi3p8HLzwfaGe4qHpYdLM7FN1tzjwXpMEc9JJzwnoCBtf
type: Opaque

オブジェクトストレージの準備

IBM Cloud Object Storage のインスタンスを設定して、バケット argo-workflow-artifacts を作成して、サービス資格情報を作成する。この時、HMACを設定しておく。

icos-cred.yaml
apiVersion: v1
kind: Secret
metadata:
  labels:
    app: argo
  name: my-icos-cred
stringData:
  accesskey: 20ae470bb23348f4adwdw4d780d8c8139
  secretkey: 0905424439cefa9f5b0b52975484964eee3f4e28617c6b12
type: Opaque

Argo workflow の起動

Argo workflow の マニフェスト を分解して、内容を理解しやすいようにして、GitHub https://github.com/takara9/argo-workflow へ登録した。

$ git clone https://github.com/takara9/argo-workflow
$ cd argo-workflow

ローカルへクローンした後、前述のように作成した postgresql-cred.yaml と icos-cred.yaml を作成する。そして、クラスタへ適用する。

$ kubectl apply -k ./

反対に、削除するときは、kubectl delete -k ./とすれば良い。次のように表示されるようになったら起動が完了しているので、次へ進む。

$ kubectl get pod 
NAME                                  READY   STATUS    RESTARTS   AGE
argo-server-7d7644fbd8-mvfw9          1/1     Running   0          31s
workflow-controller-9ddc4456d-vfkn8   1/1     Running   0          31s

Argo workflow コンソールの起動

ポートフォワードで、ローカルのポート番号にバインドして、アクセスする。

$ kubectl -n argo port-forward deployment/argo-server 2746:2746

これで、http://127.0.0.1:2746 で Argo workflow の画面が表示される。

ss-1.png

テスト実行

UPLOAD FILEのアイコンから https://github.com/argoproj/argo/tree/master/examples 中から hello-world.yaml のラベルを修正して実行する。 もちろん、事前にローカルへクローンしておく必要がある。

ss-2.png

「+ SUBMIT NEW WORKFLOW」をクリックして、バッチ処理をサブミットする。

橙色いアイコンが表示されるので、クリックすると、ポッドとしてのコンテナの起動状況を確認できる。そして、ジョブが完了したら、出力結果がオブジェクトストレージに保存されていることを確認できる。

ジョブがフェイルするケースも載せておく。次は、dag-contiue-on-fail.yaml の実行例で、各ステップの出力は、アイコンをクリックして、OUTPUT ARTIFACTS から、オブジェクトストレージに保存された内容を表示してみることができる。

実際のバッチジョブを利用する場合には、データの前処理結果などをオブジェクトストレージに保存することになる。出力先がオブジェクトストレージなので、ワークディスクが満杯でジョブネットが異常終了といったことも、起きることは無いだろうし、便利だと思う。

ss-3.png

まとめ

Kubernetesでオペレーターを利用して、データベースサービスを使うことに慣れていない点や、PostgreSQLの設定が良く知らないため、手間取ったが、オペレーターを利用してデータベースを使用すると、細かな設定は全てオペレータが代行してくれるので、非常に便利だと感じた。IBM オブジェクトストレージは、もともと Claversave と呼ばれた S3互換に開発されたオブジェクトストレージなので、HMACを指定して認証情報を取得できれば、問題なく繋がる。
アルゴ ワークフローで、ジョブネットが編集できて、YAMLを出力できたら便利なんだろうなぁと思うが、これからの発展に期待したい。 Argo CD と Argo Event についても試してたい。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?