xargsの結果をリダイレクトでファイルに出力する時に無限ループにしない

特定のディレクトリにあるファイルを全部catして、結果をファイルに保存したい時に最初に以下のように書いてみた。

 find . -type f | xargs cat > all.txt

やってみるとわかるが、これだと無限に実行が終了せずにall.txtにどんどんデータが書き込まれてファイルサイズが巨大になっていく。

対処

対処法としてはxargsで直接catに渡さずにshコマンドを経由して実行すると解決した

find . -type f| xargs -I@ sh -c 'cat "@" >> names.txt '

ワイがお世話になっているKubernetes関連のツール達

Kubernetes関連のツールで普段よくお世話になっているツール達を紹介します。 ここには無いオススメツールがあればぜひtwitter: @tomiokasyogoに教えていただけるととても喜びます。

TL;DR

k9s

github.com

UIがリッチなkubernetes用のCLIbrewなら

$ brew install derailed/k9s/k9s

でインストール出来る。

起動する時には基本的にこれ。

$ k9s

Deployment、Pod、Logなどすべてのリソースをいい感じのUIで確認できて、vimライクなコマンド操作でスムーズに操作が可能 ワードでの絞り込みも簡単にかけられる。また設定ファイルを書くとUIをカスタマイズすることも可能

kupe-ps1

github.com

自分が今、どのクラスタ・namespaceを触っているかをコマンドラインに出してくれるツール。オペミスを防ぐために必須。

$ brew update
$ brew install kube-ps1

をした後に Zshなら

source /path/to/kube-ps1.sh
PROMPT='$(kube_ps1)'$PROMPT

Bashだと

source /path/to/kube-ps1.sh
PS1='[\u@\h \W $(kube_ps1)]\$ '

としておくと、Promptで今、どのクラスタを触っているかが分かる。prd, stgクラスタは赤、devなら青とかしておくとよりわかりやすい。 (下はdocker-for-desktop) f:id:tomiokasyogo:20200310224528p:plain

kubectx

github.com

kubernetesクラスタをコマンド一つで切り替えられる macOSなら

$ brew update
$ brew install kubectx

で入れられる ただ、kubect まで kubectlまでと同じで補完が微妙なので私は alias kx="kubectx"エイリアスに設定している

kxまで打って、あとはTab連打で以下のようにpecoが接続先クラスタを出してれる。 f:id:tomiokasyogo:20200310225233p:plain

stern

github.com

「ワイはただ、ログをええ感じにgrepしたいだけなんや...!」という人におすすめ。

複数Pod、Deploymentを跨いだログも簡単に出せるのでログを見るときはだいたいsternを使ってる option等も豊富で色々できるが、とりあえず

$ stern ${Deployment名} |grep xxxx

だけでも十分なくらい優秀。

kube-forwarder

kube-forwarder.pixelpoint.io

これまでCLIが多かったが、これはGUI。 port-forward先をコンテキストごとに複数登録できて、使いたいときにはボタン一つで簡単にport-forwardを開始できる。 makefileとかで頑張ってる人はこれに乗り換えると幸せになれるかも。 ただgrpcで使うと微妙にうまく動作しないことがある。

f:id:tomiokasyogo:20200310230111p:plain

https://github.com/txn2/kubefwdGUIはやだよ、CLIじゃ無いと無理!って人は kubefwdとかいいんじゃないんでしょうか

github.com

Kubernetes Meetup Tokyo #26参加日記

12/3に開催されたKubernetes Meetup Tokyo #26にブログ枠で参加して来ました。

簡単なメモ程度ですが記事させていただきます。

イベントのcannpassのページはこちらです

KubeCon + CloudNativeCon North America 2019 Overview

まずはIan LewisさんによるKubeCon全体の振り返りです。 KubeConの参加者は年々増えており、今回のKubeConでは12000近い参加者が参加していたそうです。また、各国別の参加者ではなんと日本が3番目に多かったそうです f:id:tomiokasyogo:20191207143708p:plain

他にも印象的だったKeynoteの紹介などがされていました

Your Path to Production Ready Kubernetes hosted by Weaveworks

土田 智大さん (dullest), 楽天株式会社

Keynote: Seamless Customer Experience at Walmart Stores Powered by Kubernetes@Edge

Junichi Yoshise さん(@jyoshise), Hewlett Packard Enterprise

https://www.youtube.com/watch?v=sfPFrvDvdlk

  • もともとクラウドに置いていた物をedgeに置いた
  • エッジコンピューティングのメリット: low latency, 大規模データを扱うので、通信の問題、接続が失われた場合でもエッジで独立して対処できる。クラウドに頼らない
  • 考慮しなければいけない問題が多そう
  • 店舗にラックおくのはきつい
  • EdgeのケースはMobile
  • KubeEdge: https://github.com/kubeedge/kubeedge
  • ServiveMesh(特定のサービスだけクラウドに流したいみたいな)はIstioで
  • 息を吸うようにOperaoter作る

Running Apache Samza on Kubernetes - Weiqing Yang, LinkedIn Corporation

吉村翔太 (@yosshi_), NTT Communications

  • Apache Samza: ストリーミング処理用
  • https://github.com/apache/samza
  • 他はSpark, Flink
  • 新versionとサポートの期限の違いが1年しかない
  • Linkdinで開発され、2011年にOSS
  • pertition: サーバーがpersition分作成される
  • Samzaの説明はあまり理解しきれなかった...

How Yelp Moved Security From the App to the Mesh with Envoy and OPA

鳥居隆史 さん(@ttorii0609), Dell EMC

  • サンディエゴの雨が6ヶ月ぶりだった
  • 注目したのはSerivceMeshとSecurity
  • Default クラスタのセキュリティはざる
  • OPAに注目していた
  • computerと人間の両方を認証しよう
  • マイグレーションはエンドユーザにやらせず自動化する
  • ここまで統一かされていればよいが実際のプロジェクトでそこまでできるかはイメージできない
  • プロセスをテクノロジーに合わせていく姿勢、ツールは自作

The Release Team Shadow Program - Mentoring For the Future - Guinevere Saenger, GitHub & Lachlan Evenson, Microsoft

Yang Li (@idealhack), Kubernetes community

Kubernetes Meetup Tokyo #25に参加してきた

Kubernetes Meetup Tokyoとは

Kubernetes Meetup Tokyoは、Kubernetesのユーザが集まり、KubernetesKubernetes周辺のソフトウェアについて、情報交換、交流をするイベントとなっています。

k8sjp.connpass.com

※当日の様子は下記で配信されています

www.youtube.com

入門、Kubernetes Persistent Volume

発表者: 坂下 幸徳(Twitter: @ysakashita3, GitHub: ysakashita), 所属: ゼットラボ株式会社

KubernetesのPV(Persistent Volume)に関する発表でした。用語の整理から、ストレージの種別、k8s内部における動き、よくあるQAなどとても丁寧にまとまった内容で、普段PVを頻繁に利用していない私でもスムーズに理解することができました。

PVに不安を感じる方はぜひ一度見て見ると良いと思います

speakerdeck.com

KubernetesにおけるCSIについて

発表者: 早川 大貴 (Twitter: bells17_, Github: bells17), 所属: 株式会社IDCフロンティア

Kubernetesなどのコンテナオーケストレータにおけるストレージを利用する際の共通仕様であるCSI (Container Storage Interface)に関する発表でした。

CSIが必要とされている背景や、CSIによってどういった点が定められているのかがまとめられていて興味深い内容でした。 またボリュームプラグインソースコードKubernetesから除外することで、Kubeletなどのimageのサイズが小さくできるのも嬉しいと感じる点でした。

speakerdeck.com

How to develop the high-available Redis database application on Kubernetes

発表者: Ran Xu (Github: fengzixu Twitter: Haierdi0715)

最後のセッションは英語での発表でした。 調べたのですがスライドは確認できませんでした。

内容としてはRedis ClusterをマネジメントするOperatorに関する内容でした。

@inductorさんがTwitter上で実況してくださっていたのがとてもわかりやすくて助かりました

⬇︎このあたりから [https://twitter.com/inductor/status/1194573349914988544:embed]

Kuberneteはクラスタ管理やインフラ管理に長けていることを利用し、高信頼性なデータ保持性、高可用性をもったRedis Clusterを構築することが目的のようでした。

時間の関係上スキップされた内容が多かったのですが、Redis Clusterを関するControllerやRedis ClusterにアクセスするためのSLB (Super Load Balancer)と呼ばれるLBを実装した話がとても印象的でした。

発表の最後にこのRedis OperatorがOSS化される準備ができているとのことをおっしゃられていたので公開されるのが待ち遠しいです。

LT

LTは予定の都合により参加できなかったのですが、どれも面白い内容+参考になる情報が盛りだくさんでした。

※LTを含むスライドはこちらで確認できます

k8sjp.connpass.com

Workload-identityでGKEのPodに権限を与える

従来のGKEでの認証情報の渡し方

既存のGKEクラスタでは使用したリソースへのアクセス・編集権限を持ったGCPのサービスアカウントを発行し、サービスアカウントのjsonキーをkubernetesリソースであるSecretに登録し、マウントすることでアプリケーションから他のGCPリソースへのアクセス権限を渡していると思います。

しかし、この手法ではSecretをどの様に管理するかによってセキュリティリスクが大きく異なります。KMSなどのKey Management Serviceを利用することでセキュリティリスクを削減することも出来ますが、それでもjsonファイル一つで認証情報がすべてわかってしまう為、キーが漏洩する危険性は常に付きまとっています。

Workload Identity

Workload IdentityとはGKE上で動作しているPodがGCSなどの他のGCPリソースを使用する際の認証情報を渡す為の手法です。

Workload IdentiyではKubernetes上のServiceAccountとGCP上のServiceAccountを紐づけることでサービスアカウントの認証情報を直接Podに渡すことなく認証を行うことができる手法です。 (このブログでは両方が”ServiceAccount”では説明がややこしくなってしまうので、公式ドキュメントになぞってKubernetesのリソースであるServiceAccountをKSA、GCPの認証用アカウントであるServiceAccountをGSAとしています)

Google Cloud Nextで登場したスライドの図がとてもわかりやすくなっています。最後に発表のリンクを貼っておきます f:id:tomiokasyogo:20190916232504p:plain

KSAとGSAを紐づけることで、図の様にMetadata Serverからアクセストークンを取得し利用することが出来ます。

実際に使ってみる

それでは実際に使ってみたいと思います

準備

workload-identityを有効にしたGKEクラスタを作成します

$ gcloud beta container clusters create ${cluster-name} \
  --cluster-version=1.12 \
  --identity-namespace=${project-id}.svc.id.goog \
  --zone=asia-northeast1-c

次にGSAを作成します。この時点ではなんの権限も付与していません

$ gcloud iam service-accounts create workload-identify-sa-k8s

次にクラスタ内に新しくechoというnamespaceと、echonamespace内に今回使用するKSAを作成します

  • namespaceの作成
$ kubectl create namespace echo
  • KSAの作成
$ kubectl create sa -n echo workload-identify-sa

次に2つのGSAとKSA間にCloud IAMポリシーバインディングを作成して、KubernetesサービスアカウントがGoogleサービスアカウントを使用できるようにします。このバインドにより、KubernetesサービスアカウントがGoogleサービスアカウントとして機能できるようになります。

$ gcloud iam service-accounts add-iam-policy-binding \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:${project-id}.svc.id.goog[echo/workload-identity-sa-k8s]" \
workload-identify-sa@${project-id}.iam.gserviceaccount.com

GCP側の設定が完了したので、次にKSA側にGSAの情報を付与します。 付与する時にはKSAにGKA名が入ったアノテーション を追加することで付与することができます

$ kubectl annotate sa \
--namespace echo \
workload-identity-sa-k8s  \
iam.gke.io/gcp-service-account=workload-identify-sa@${project-id}.iam.gserviveaccount.com

$ kubectl describe sa -n echo workload-identity-sa-k8s
Name:                workload-identity-sa-k8s
Namespace:           echo
Labels:              <none>
Annotations:         iam.gke.io/gcp-service-account: workload-identify-sa@${project-id}.iam.gserviveaccount.com
Image pull secrets:  <none>
Mountable secrets:   workload-identity-sa-k8s-token-6qhd4
Tokens:              workload-identity-sa-k8s-token-6qhd4
Events:              <none>

KSAではSAに紐づくTokenがSecretとして同時に作成されます。 ServiceAccountをDeployment等で指定すると同時にSecretが/var/run/secrets/kubernetes.io/serviceaccountにマウントされてKSAのTokenや証明書の情報を参照することができます。

実際にKSAとGSAが紐づいているかを確認する

google/cloud-sdkのイメージを利用して実際にKSAとGSAが紐づいているのかを確認します。 下記のコマンドで一時的なPodをデプロイします

$ kubectl run -it \
  --generator=run-pod/v1 \
  --image google/cloud-sdk \
  --serviceaccount workload-identity-sa-k8s \
  --namespace echo \
  workload-identity-test

デプロイが完了するとターミナルがPod内でコマンドを実行することができるので

$ gcloud auth list

とタイプしてみましょう。そうすると先ほど指定したGSAのリストがActivateされていることが確認できると思います。

実際にアプリケーションから利用する

実際にアプリケーションから非公開のGCSバケットにアクセスしてデータを取得してみようと思います。 以下のコマンドでバケットを作成し、適当なファイルをおきます

$ gsutil mb gs://workload-identity
$ gsutil cp aa.txt gs://workload-identity/aagsutil cp aa.txt gs://workload-identity/aa.txt

次にバケットの読み取り権限を付与します

$ gsutil acl ch -u gcs workload-identify-sa@${project-id}.iam.gserviveaccount.com:READER gs://workload-identity/aa.txt

あとは以下の様なコードを書くことでGCSのオブジェクトを読み込むことができます

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"

    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
)

func main() {
    http.HandleFunc("/", helloWorld)
    http.ListenAndServe(":8080", nil)
}

func helloWorld(w http.ResponseWriter, r *http.Request) {
    ctx := context.Background()
    ts, err := google.DefaultTokenSource(ctx)
    if err != nil {
        fmt.Fprintf(w, "Can't read object!,%s", err)
        return
    }
    gcs := oauth2.NewClient(ctx, ts)
    resp, err := gcs.Get(fmt.Sprintf("https://storage.cloud.google.com/%s/%s", "workload-identity", "aa"))
    if err != nil {
        fmt.Fprintf(w, "Can't read object!,%s", err)
        return
    }
    defer resp.Body.Close()
    io.Copy(w, resp.Body)
}

DefaultTokenSourceのコメントに書いてありますが DefaultTokenSourceは以下の様な順番でクレデンシャル情報を探します

// It looks for credentials in the following places,
// preferring the first location found:
//
//   1. A JSON file whose path is specified by the
//      GOOGLE_APPLICATION_CREDENTIALS environment variable.
//   2. A JSON file in a location known to the gcloud command-line tool.
//      On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
//      On other systems, $HOME/.config/gcloud/application_default_credentials.json.
//   3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses
//      the appengine.AccessToken function.
//   4. On Google Compute Engine, Google App Engine standard second generation runtimes
//      (>= Go 1.11), and Google App Engine flexible environment, it fetches
//      credentials from the metadata server.

今回の場合、4番にある様にGKEのMetadata Serviceに問い合わせ、IAMからTokenを取得することでアクセスが可能になっています。 コードだとこの辺りでしょうか

https://github.com/golang/oauth2/blob/master/google/default.go#L107-L113

 // Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime,
    // or App Engine flexible, use the metadata server.
    if metadata.OnGCE() {
        id, _ := metadata.ProjectID()
        return &DefaultCredentials{
            ProjectID:   id,
            TokenSource: ComputeTokenSource("", scopes...),
        }, nil
    }

運用を考えて

実際にWorkload-identityを使用する場合、現状のGSAをSecretで渡す形式より良いと感じる部分は以下の点です

  • KSAと紐づけられるのでキー漏洩の心配が無くなる
  • KSAはnamespaceで区切れる=namespaceごとに開発チームを分けることで、管理がしやすくなる

ただ、使用する際にはマニフェストのAnnotationに書くだけなのでnamespaceのKSAを指定しておけば紐づくGSAも使えてしまうというのは少し気になります。(Secretを利用した場合でも同じですが) ちゃんとやるなら開発チームやサービスごとにnamespaceを分けるのは必須の様な気がします。

総合的にみるとGCP内で認証プロセスが完結し、開発者が認証情報を直接触らなくていいだけでかなりメリットが大きい機能だと思います。 認証プロセスだけ少し複雑なのでちゃんと理解する必要がありますが、ぜひ使っていきたい機能ですね。

参考サイト、発表

https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity

www.youtube.com

KnativeなCI/CDツールのTektonを使って、GKE上でイメージのビルド、GKEへのデプロイを行う

What is Tekton?

Tektonk8sネイティブなCI/CDを構築するためのプロジェクトです。 CDF (Continuous Delivery Foundation)のメンバーでもあります。

f:id:tomiokasyogo:20190506004157p:plain

Tektonの目指しているゴールとしてはクラウドプラットフォームやオンプレ環境などに依存しないCI/CD環境を構築することのようです。

READMEを参考にするとTektonは、

1. Cloud Native

・Kunernetes上で実行可能

・コンテナを実行ブロックの単位として扱える

2. Decoupled

・一つのパイプラインで複数のクラスタにデプロイできる

・パイプラインを構築するTaskは単独で実行可能

・複数のgitリポジトリを簡単に扱える

3. Typed

・リソースは入力によって変更可能

(例:例えばImageのビルドを簡単にkanikoにしたりbuildkitにしたりできる)

Tektonに関してもっとよく知りたい方にはCloud Next '19の以下のセッションが参考になると思います。

www.youtube.com

Tektonに登場する概念

Tektonに登場する概念ついて説明します。

Step

もっとも基本的な単位、kubernetesのPodと同じように定義できる

Task

複数のStepによって構成される。Stepごとに動作させるコンテナやリソースは指定できる。

Pipline

Taskを組み合わせたもの、実行する順番などを指定することもできる。また、複数あるTaskは同じノードで実行される訳ではない。

f:id:tomiokasyogo:20190505192759p:plain f:id:tomiokasyogo:20190505192947p:plain

PiplineResources

Taskで利用されるインプットやアウトプットを指定するためのリソースとしてPiplineResourcesがあります。 例えば、

・TaskにインプットとしてGitHubソースコードを利用

・TaskのアウトプットとしてDockerイメージを作り出す。また、作ったイメージはGCRやDockerHubなどのイメージレジストリーにPushされる

といった場合にそれぞれの入力や出力をPiplineResourcesを利用して定義します。

TaskRun && PipelineRun

TaskやPipelineを実際に実行するためのリソースがTaskRunPiplineRunです。 TaskRunPipelineRunではこれまでに定義したTask、Pipelineに対してPipelineで定義したリソースおよび、トリガーの情報、引数などを実際に渡します。 イメージとしてはTask、Pipelineでどのようなタイプのリソースを使ってどんな処理をするのかを定義しておいて、TaskRunとPipelineRunで実際のリソースを渡してあげるようなイメージです。

PipelineResourceとTask、TaskRunの関係を大雑把に示したものが以下の図になります。Pipelineは少し違いますが考え方は大体同じです。

f:id:tomiokasyogo:20190505195412p:plain

それでは実際に、Tektonを使ってGoのコードのテスト、Dockerイメージのビルド&GCRへのプッシュ、GKEへのデプロイを行って行きます。

下準備

GKEクラスタの構築とTektonのデプロイ

Google Cloudのクイックスタートを参考にして、GKEクラスタを構築、およびkubectlコマンドでGKEクラスタにアクセスできるようにしてきます。

またこちらを参考にcluster-admin権限を取得、TektonPipelineリソースをGKEにデプロイします。TektonリソースはCRDsとしてデプロイされるのでコマンド一つでGKE上で使用できるようになります。

Kanikoのためのサービスアカウントの登録

今回はDockerイメージのビルドにKanikoを利用しているのでこちらのサイトを参考にしてGCRのeditor権限を持ったサービスアカウントを作成してSecretとして登録しておきます。今回は単にSecretとして利用していますが、プロダクションで利用する際にはKMSなどを使用した方がセキュリティ的に安全です。

ClusterRoleBindの設定

今回のデモではkubernetesクラスタにデプロイするので、クラスタのAdmin権限を持ったServiceAccountが必要になります。exampleのClusterRoleBindingリソースを参考にAdmin権限を付与したServiceAccountを登録します。今回の例ではdefaultに付与しています。GKEにうまくデプロイできない場合にはこのあたりをもう一度見直す必要があります。

流れ

今回のデモでは、

  1. Goアプリケーションのテスト
  2. Dockerイメージのビルド
  3. kubectlコマンドでGKEクラスタにそのままデプロイ

の順番で行います。

今回使用したソースコードこちらにおいてあります。

PipelineResourcesの登録

まずはPipelineで利用するPipelineResourcesを登録します。

今回使用するリソースは、アプリケーションのGitHubリポジトリのURLと、イメージをPushするGCRを指定しています。以下のようなYamlファイルを用意してapplyします。

apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: tekton-sample-resource-image
spec:
  type: image
  params:
    - name: url
      value: gcr.io/${YOUR_PROJECT}}/tekton-sample-image  # modify to your GCR path.
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: tekton-sample-resource-git
spec:
  type: git
  params:
    - name: revision
      value: master
    - name: url
      value: https://github.com/tommy-sho/tekton-sample.git # modify to your git repository

ここで重要なのは、spec.typeの部分です。Tektonでは各リソースの種類がtypeとして指定されています。

kubectl get PipelineResourcePipelineResourceが以下のように登録されていることが確認できます。

NAME                           AGE
tekton-sample-resource-git     6m
tekton-sample-resource-image   6m

Taskの登録

イメージのビルドとプッシュ

次にTaskを登録します。KanikoによるDockerイメージのビルドとGCRへのプッシュを行うタスクを以下のようなYamlファイルで定義します。

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: build-image
spec:
  inputs:
    resources:
      - name: app
        type: git
    params:
      - name: pathToDockerFile
        description: The path to the dockerfile to build
        default: /workspace/app/Dockerfile
      - name: pathToContext
        description: The build context used by Kaniko (https://github.com/GoogleContainerTools/kaniko#kaniko-build-contexts)
        default: /workspace/app/  # <- ここのpathはworkspace/resource名/のプレフィックスがつく
  outputs:
    resources:
      - name: builtImage
        type: image
  steps:
    - name: build-and-push
      image: gcr.io/kaniko-project/executor
      command:
        - /kaniko/executor
      args:
        - --dockerfile=${inputs.params.pathToDockerFile}
        - --destination=${outputs.resources.builtImage.url}
        - --context=${inputs.params.pathToContext}
      volumeMounts:
        - name: kaniko-secret
          mountPath: /secret
      env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /secret/kaniko-secret.json
  volumes:
    - name: kaniko-secret
      secret:
        secretName: kaniko-secret

ここで注意する必要があるのはparmsで指定しているpathのプレフィックスです。現在(2019/5)では、type:gitPipelineResource/workspace/リソース名以下に配置されます。今回は、input.resourceappという名前のリソースにしているので/workspace/app以下にGitHubのコードが展開されます。

GKEへのデプロイ

GKEへのデプロイはkubectlが利用できるlachie83/k8s-kubectlイメージを利用しました。Yamlファイルは以下のようになっています。

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: deploy-kubectl
spec:
  inputs:
    resources:
      - name: app
        type: git
    params:
      - name: path
        description: Path to the manifest to apply
  steps:
    - name: run-kubectl
      image: lachlanevenson/k8s-kubectl
      command: ['kubectl']
      args:
        - 'apply'
        - '-f'
        - '${inputs.params.path}'

単純にkubetcl applyを叩いているだけです。デプロイに使うマニフェストを渡しています。

Pipelineの設定

さて、PipelineResourceとTaskが定義できたのでいよいよPipelineを定義していきます。Pipelineを定義したYamlファイルは以下のようになっています。

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: sample-pipline
spec:
  resources:
    - name: app
      type: git
    - name: image
      type: image
  tasks:
  - name: build-push-image
    taskRef:
      name: build-image
    params:
      - name: pathToDockerFile
        value: /workspace/app/Dockerfile
      - name: pathToContext
        value: /workspace/app
    resources:
      inputs:
      - name: app
        resource: app
      outputs:
      - name: builtImage
        resource: image
  - name: deploy
    runAfter: [build-push-image]
    taskRef:
      name: deploy-kubectl
    params:
      - name: path
        value: /workspace/app/manifest.yaml
    resources:
      inputs:
      - name: app
        resource: app

特に難しいことはありません。spec.resourcesでPipelineの中で利用するPipelineResourceを定義しておいて、spec.tasksで実行するTaskを並べています。 また、それぞれのTaskに対して、使用するparamsresourcesを定義します。

もしTaskに実行する順番(ex. line -> test -> build -> deployなど)がある場合には、runAfterで依存関係を明示することができます。宣言しなかった場合にはそれぞれPodが立って並列で実行されます。

PipelineRunの定義

さてまだあります。PipelineRunです。Pipelineでは最初にPipelineResourceを定義して、Taskの中でどのresourceを使用するかを定義していますが、またresourceのタイプのみしか明らかになっていないので、PipelineRunで実際にどのPipelineResourceを使用するのかを宣言します。

PipelineRunは以下のようにしました。

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: pipeline-run
spec:
  pipelineRef:
    name: sample-pipline
  trigger:
    type: manual
  resources:
    - name: app
      resourceRef:
        name: tekton-sample-resource-git
    - name: image
      resourceRef:
        name: tekton-sample-resource-image

使用するPipelineResourcetriggerが定義されています。最初の方で定義したPipelineResourcePipelineを結びつけています。

現在(2019/5)ではtriggerGitHubへのPushや、Slackなどを使ったチャットオペレーションには対応していない状態です。こちらのRoadmapによると2019年以内には対応する予定のようです。

実際にPipelineRunしてみる

これで準備ができたので、今までに定義したリソースをapplyした後で、PipelineRunをapplyしてみます。

kubectl get tekton-pipelinesコマンドでTektonPipelineのリソースが確認できます。

$ > kubectl get tekton-pipelines
NAME                                 AGE
pipeline.tekton.dev/sample-pipline   2m

NAME                                  STATUS   STARTTIME   COMPLETIONTIME
pipelinerun.tekton.dev/pipeline-run   True     2m          37s

NAME                                                       AGE
pipelineresource.tekton.dev/tekton-sample-resource-git     2m
pipelineresource.tekton.dev/tekton-sample-resource-image   2m

NAME                             AGE
task.tekton.dev/build-image      2m
task.tekton.dev/deploy-kubectl   2m

NAME                                                     SUCCEEDED   REASON   STARTTIME   COMPLETIONTIME
taskrun.tekton.dev/pipeline-run-build-push-image-6jbcm   True                 2m          43s
taskrun.tekton.dev/pipeline-run-deploy-782tv             True                 43s         37s

一番下の部分がPipelineの中の各TaskでSUCCEEDEDTrueになっていることがわかります。 Taskが正しく完了しなかった場合にはSUCCEEDEDFalseになります。 実際にGKEにデプロイされたかどうかを確認します。

$ > kubectl get pods
NAME                                             READY   STATUS      RESTARTS   AGE
pipeline-run-build-push-image-dhjvh-pod-51492d   0/3     Completed   0          1m
pipeline-run-deploy-wr7cm-pod-1a4ff9             0/3     Completed   0          26s
sample-6d96898c4c-hk847                          1/1     Running     0          20s
sample-6d96898c4c-tr4hd                          1/1     Running     0          20s

正しくデプロイされているようです。Taskで利用されたPodも確認できます。

 まとめ

KnativeなCI/CDツールとして期待されているTektonを触って見ました。 今回は触っていませんが、DashBoradを作成してPipelineの実行状況の確認などもできるようです。 リポジトリをみるとTekton自体まだ開発が始まって間もないプロジェクトなのでまだ機能的には足りないと感じる部分はありますが、Kubernetes上でCI/CDパイプラインを構築できる点やカスタマイズ性の高さは触っていても非常に高いと感じたのでこれからの開発に要注目して行きたいとおもいます。 あとこのマスコットキャラも近未来感があって好きだったりします。

もし、うまく動かない、記事に変な点があったりする場合には気軽にコメントや連絡してください。

参考サイト、記事

github.com

github.com

github.com

www.youtube.com

GKEクラスタ内からMemoryStoreにアクセスするならIP エイリアスを有効に

IPエイリアス

IPエイリアスに関してはこちらの公式サイトにて説明があります。 IPエイリアスを有効にすることで、GCPの他のプロダクトやサービスを操作できるようになります。

公式サイトにある手順の中で、IPエイリアスを設定する部分をよく読まずにGKEクラスタをぽちぽち立てていたところ、GKEのクラスタ内部からMemoryStoreにアクセスできない事案が発生しました。調べた結果IPエイリアスが無効(Disable)になっておりMemoryStoreにアクセスできない状態だったみたいです。

IP エイリアスを有効にする

IPエイリアスを有効にするためには、GKEクラスタを立ち上げる際に、

gcloud container clusters create visitcount-cluster --num-nodes=3 --enable-ip-alias

引用:https://cloud.google.com/memorystore/docs/redis/connect-redis-instance-gke

のように--enable-ip-aliasをオプションでつけることで有効にすることができます。

コンソールから設定する場合にはNetworkingEnable VPC-native (using alias IP)にチェックを入れることで有効にできます。(下図)

f:id:tomiokasyogo:20190501164336p:plain

しかし、下にも書いてあるようにもうすぐデフォルトで有効になるようなので必要なのは今だけだと思います。