kubernetes
Concourse
Z LabDay 11

zlabjp/kubernetes-resource を使う

More than 1 year has passed since last update.

概要

今日は、zlabjp/kubernetes-resource を実際に使うというのをやります。kubernetes-resource は、k8s にアプリケーションをデプロイするための concourse リソースです。ゼットラボで必要に迫られて作って、それから便利に使っています。@superbrothers による初日の記事の通りです。ツールというのは、あれこれ触ってみると理解が進みます。手元に k8s クラスタと concourse があって、GitHub と Docker Hub を利用できる環境であれば、同じことができるはずです。よかったら一緒にやりましょう。

やること

あらかじめ k8s に nginx-1.13.6 をデプロイしておいて、concourse から nginx-1.13.7 にアップデートします。あらかじめの方は、手元の PC から個人の権限でデプロイします。アップデートの方は、GitHub リポジトリの Tag の作成をトリガーにして、concourse から ServiceAccount の権限でデプロイします。k8s と kubectl のバージョンは、ともに v1.7.11 を使います。大きくは、準備して実行するだけです。

準備

GitHub → k8s → concourse の順に準備します。

GitHub

今回は、bhiro/myproject というリポジトリを新しく Private で作りました。README.md もリポジトリと一緒に作りました。これを手元の PC に git clone します。

$ git clone git@github.com:bhiro/myproject.git
$ cd myproject

このリポジトリを concourse から Read するための Deploy key を作成します。Deploy Key の実体は、SSH キーペアです。このキーペアは、concourse が使います。パスフレーズは設定してはいけません。no passphrase でないと concourse のジョブが失敗します。作成した鍵は、secrets ディレクトリに保存します。

$ mkdir secrets
$ ssh-keygen -t rsa -b 4096 -C "" -f secrets/id_rsa

公開鍵は、GitHub リポジトリの Deploy Keys に Read only の設定で登録します。秘密鍵は、あとで concourse パイプラインに登録します。

secrets
├── id_rsa
└── id_rsa.pub

secrets ディレクトリは、誤って Git にコミットしないように、.gitignore に書いておきます。

/secrets

k8s

定義ファイルを作ってから、k8s リソースを作ります。

定義ファイル

k8s の定義ファイルを作ります。作り終えると、手元の PC のディレクトリは、以下のようになります。

myproject
├── .git
├── .gitignore
├── README.md
├── deploy
│   └── nginx-deploy.yaml
├── k8s
│   ├── 0_ns.yaml
│   ├── role.yaml
│   ├── rolebinding.yaml
│   └── sa.yaml
└── secrets
    ├── id_rsa
    └── id_rsa.pub

k8s ディレクトリには、クラスタ向けの定義ファイルを置きます。deploy ディレクトリには nginx 向けの定義ファイルを置きます。以下は、定義ファイルの一覧です。

定義ファイル リソース種別 リソース名
k8s/ns.yaml Namespace dev
k8s/sa.yaml Service Account deploy
k8s/role.yaml Role deploy
k8s/rolebinding.yaml RoleBinding deploy
deploy/nginx-deploy.yaml Deployment nginx

ファイルの内容は以下の通りです。

dev ネームスペースです。

k8s/ns.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: dev

deploy という ServiceAccount と Role を作って、それらをバインドします。これらのリソースは、dev ネームスペースに置きます。

k8s/sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: deploy
  namespace: dev
k8s/role.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: deploy
  namespace: dev
rules:
- apiGroups: [""]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["extensions"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["autoscaling"]
  resources: ["*"]
  verbs: ["*"]
k8s/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: deploy
  namespace: dev
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deploy
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: system:serviceaccount:dev:deploy
  namespace: dev

nginx-1.13.6 をデプロイするための、Deployment です。

deploy/nginx-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.13.6
        name: nginx

リソース

kubectl コマンドを使って、手元の PC から k8s リソースを作ります。先にクラスタ向けのリソースを作ります。

$ kubectl apply -f k8s/

それから、nginx 向けのリソースを作ります。

$ kubectl apply -f deploy/ --namespace=dev

すでに定義ファイルがあるので簡単ですね。
pod が Running で nginx-1.13.6 のイメージなら OK です。

$ kubectl get pod --namespace=dev
NAME                     READY     STATUS    RESTARTS   AGE
nginx-1161159442-nlvzx   1/1       Running   0          5m

$ kubectl describe pod nginx-1161159442-nlvzx --namespace=dev |grep 'Image:'
Image:          nginx:1.13.6

concourse

定義ファイル

concourse の定義ファイルを作ります。作り終えると、手元の PC のディレクトリは、以下のようになります。

myproject
├── .git
├── .gitignore
├── README.md
├── concourse
│   └── pipeline.yaml
├── deploy
│   └── nginx-deploy.yaml
├── k8s
│   ├── 0_ns.yaml
│   ├── role.yaml
│   ├── rolebinding.yaml
│   └── sa.yaml
└── secrets
    ├── concourse-secrets.yaml
    ├── id_rsa
    └── id_rsa.pub

concourse ディレクトリにパイプライン向けの定義ファイルを置きます。秘密情報は、Git にコミットされないように secrets ディレクトリに置きます。以下は、定義ファイルの一覧です。

定義ファイル
concourse/pipeline.yaml
secrets/concourse-secrets.yaml

pipeline.yaml の内容は以下の通りです。

最初に kubernetes-resource の定義があります。tag は、デプロイ先の k8s のマイナーバージョンに合わせてセットします。今回のデプロイ先は k8s-v1.7.11 なので、tag: "1.7" としています。{{key}}{{config}} は秘密情報です。パイプライン作成時に、concourse-secrets.yaml から展開します。

concourse/pipeline.yaml
resource_types:
- name: kubernetes
  type: docker-image
  source:
    repository: zlabjp/kubernetes-resource
    tag: "1.7"

resources:
- name: myproject
  type: git
  source:
    uri: git@github.com:bhiro/myproject.git
    branch: master
    tag_filter: v*
    private_key: {{key}}

- name: myk8s
  type: kubernetes
  source:
    kubeconfig: {{config}}

jobs:
- name: deploy
  serial: true
  plan:
  - get: myproject
    trigger: true
  - put: myk8s
    params:
      kubectl: apply -f myproject/deploy --namespace=dev
      wait_until_ready_selector: app=nginx

次に、concourse-secrets.yaml を作ります。

concourse-secrets.yaml には、GitHub リポジトリを Read するための Deploy Key と、k8s クラスタを操作するための kubeconfig を記入します。Deploy key には、GitHub の準備で作成した SSH キーペアの秘密鍵を使います。

$ cat secrets/id_rsa > secrets/concourse-secrets.yaml
$ chmod 600 secrets/concourse-secrets.yaml

kubeconfig は、zlabjp/kubernetes-scripts に含まれる create-kubeconfig というツールを使ってジェネレートします。create-kubeconfig の引数は ServiceAccount 名です。k8s の準備で dev ネームスペースに作成した deploy サービスアカウント を渡します。

$ curl -LO https://raw.githubusercontent.com/zlabjp/kubernetes-scripts/master/create-kubeconfig
$ chmod +x ./create-kubeconfig
$ mv ./create-kubeconfig /tmp/
$ /tmp/create-kubeconfig deploy --namespace=dev >> secrets/concourse-secrets.yaml

key と config をキーとして yaml に整形します。ここは、エディタの矩形編集を使って頑張ります。

secrets/concourse-secrets.yaml
key: |
  -----BEGIN RSA PRIVATE KEY-----
  ....
  ....
  -----END RSA PRIVATE KEY-----

config: |
  apiVersion: v1
  ....
  ....
  token: ....

これで、全ての定義ファイルが揃いました。最後に GitHub に Push しておきます。

$ git add -A
$ git commit -m "create definition files"
$ git push origin master

パイプライン

fly コマンドを使って、手元の PC から concourse のパイプラインを作ります。${URL}${TEAM} は、環境に合わせてセット下さい。ターゲット名とパイプライン名は任意です。今回はそれぞれ dev, myproject としています。

$ fly --target dev login --concourse-url ${URL} --team-name ${TEAM}
$ fly --target dev set-pipeline --pipeline myproject --config concourse/pipeline.yaml --load-vars-from secrets/concourse-secrets.yaml
$ fly --target dev unpause-pipeline --pipeline myproject

すでに定義ファイルがあるので簡単ですね。
UI や コマンドラインからパイプラインが確認できれば OK です。

$ fly --target dev pipelines

実行

実行は、準備よりだいぶ簡単です。GitHub リポジトリ の Tag の作成をトリガーにして、k8s 上の nginx-1.13.6 を concourse から nginx-1.13.7 にアップデートします。

nginx-deploy.yaml を以下のように変更します。

git diff deploy/nginx-deploy.yaml
diff --git a/deploy/nginx-deploy.yaml b/deploy/nginx-deploy.yaml
index ec17270..4a8c9a9 100644
--- a/deploy/nginx-deploy.yaml
+++ b/deploy/nginx-deploy.yaml
@@ -14,5 +14,5 @@ spec:
         app: nginx
     spec:
       containers:
-      - image: nginx:1.13.6
+      - image: nginx:1.13.7
         name: nginx

コミットして push します。

$ git add deploy/nginx-deploy.yaml
$ git commit -m "update nginx"
$ git push origin master

最後に Tag を切ります。

$ git tag v0.0.1
$ git push origin v0.0.1

これを、トリガーに concourse の job が動きます。

$ fly --target dev builds|grep myproject
2674  myproject/deploy 1   succeeded  2017-12-06@20:04:26+0900  2017-12-06@20:04:48+0900  22s

22秒で終わりました。成功したようです。UI も job の成功を表す緑色になっています。

image.png

k8s を確認します。

$ kubectl get pod --namespace=dev
NAME                     READY     STATUS    RESTARTS   AGE
nginx-3944497639-tzk71   1/1       Running   0          3m

$ kubectl describe pod nginx-3944497639-tzk71 --namespace=dev |grep 'Image:'
    Image:          nginx:1.13.7

確かに、nginx-1.13.7 にアップデートされています。

まとめ

今日は、zlabjp/kubernetes-resource を使って、concourse から k8s へのデプロイをやりました。CI や CD の準備というのは大変なものですが、組み終わって、動き出すと、なんとも気持ちのいいものです。ぜひ、お試しください。

おわりに

このエントリは、弊社 Z Lab のメンバーによる Z Lab Advent Calendar 2017 の十一日目として業務時間中に書きました。十二日目は @TakanariKo による OpenFaaS のお話です。