2021年6月13日日曜日

Jaeger 超入門

Jaeger 超入門

概要

Jaeger は分散トレーシングシステムです 過去に Zipkin を試しましたがこれと同じような golang 製のツールになります 今回はどんなツールなのか理解するためにローカルで簡単に動作させる方法を紹介します

環境

  • macOS 11.4
  • Jaeger
  • docker 20.10.6

Jaeger の起動

Jaeger は複数のコンポーネントで構成されるツールになります UI や agent, DB などがあります プロダクションではそれぞれ個別で構築し HA 構成などを取ることが推奨されています が、ローカルで気軽に試すのはそれだと大変んです なので docker でオールインワンパッケージとしてイメージが公開されているのでそれを使うと簡単に試すことができます

docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.22

それぞれのコンポーネントで必要となるポートはホスト側でバインドして上げています これで localhost:16686 にアクセスすると Jaeger の UI を確認することができます

テスト用のアプリを起動する

HotROD という Jaeger に対応したサンプル Web アプリがあるのでこれを使います

事前に起動しておいた Jaeger に接続するために --link オプションを使います

docker run --rm -it \
  --link jaeger \
  -p8080-8083:8080-8083 \
  -e JAEGER_AGENT_HOST="jaeger" \
  jaegertracing/example-hotrod:1.22 \
  all

これで localhost:8080 にアクセスするとサンプルアプリにアクセスできます

動作確認

画面をポチポチすると Jaeger 側にトレースデータが送信されます

「find trace」をクリックすると Jager 側に登録されたトレース情報を確認することができます

最後に

docker で簡単に確認できるのは嬉しいです 実際は各種クライアントがあるのでこれを使って自分のアプリにトレース情報を送信する仕組みを作る必要があります

参考サイト

2021年6月12日土曜日

k8s で PostgreSQL Operator を試してみた (Zalando編)

k8s で PostgreSQL Operator を試してみた (Zalando編)

概要

PostgreSQL Operator は Postgres を k8s 上で簡単に構築/運用するための CustomResource を使ったオーケストレーションツールです 今回は PostgreSQL Operator を使って Postgres の構築を行ってみました

環境

  • k8s v1.20.1
  • helm v3.5.2
  • PostgreSQL Operator 1.6.3

PostgreSQL Operator のデプロイ

helm を使うと簡単です kustomize やマニフェストからデプロイする方法もありますが今回は helm を使います

最新版が Artifacthub で公開されてはいないので Github から直接チャートを展開します 以下のように Operator が展開されれば OK です まだこの時点では PostgreSQL サーバ自体はありません

NAME                                READY   STATUS    RESTARTS   AGE
postgres-operator-88f7975df-tgf77   1/1     Running   0          85s

PostgreSQL Operator UI のデプロイ

Operator には管理用の UI があり PostgreSQL の構築や管理を UI から行うことができます

  • helm install postgres-operator-ui ./charts/postgres-operator-ui

Pod がデプロイできれば OK です

デフォルトだと外部からアクセスできないようになっているので Service を編集して NodePort に変更します

  • kubectl edit svc postgres-operator-ui
type: NodePort

Service の NodePort は適宜変更してください

http://node_ip:30595/#new

で Operator の管理 UI にアクセスできます

PostgreSQL サーバの構築

管理 UI から行ってみます 先程の URL にアクセスすると PostgreSQL を作成するためのフォームが表示されます

Name や Users など好きな情報を入力して作成しましょう なお後で紹介しますが Operator 経由の PostgreSQL の構築では好きなユーザは作成できますが好きなユーザに好きなパスワードを設定することはできません 基本的には Operator が自動で生成します

作成中になるとステータスもちゃんと表示されています 完了するまで待ちましょう

作成が完了すると以下のように PostgreSQL が作成されます

  • kubectl get all -l team=acid
NAME              READY   STATUS    RESTARTS   AGE
pod/acid-test-0   1/1     Running   0          12m

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/acid-test        ClusterIP   10.107.79.204   <none>        5432/TCP   12m
service/acid-test-repl   ClusterIP   10.107.39.37    <none>        5432/TCP   12m

NAME                         READY   AGE
statefulset.apps/acid-test   1/1     12m

NAME                                 TEAM   VERSION   PODS   VOLUME   CPU-REQUEST   MEMORY-REQUEST   AGE   STATUS
postgresql.acid.zalan.do/acid-test   acid   13        1      10Gi     100m          100Mi            12m   Running

構成を変更して NodePort からアクセスできるようにしてみる

デプロイした PostgreSQL の構成も管理 UI から変更できます

作成したクラスタの「Edit」を選択すると以下のような編集画面になります

外部からアクセスできるようにするためには「enableConnectionPooler」「enableMasterLoadBalancer」「enableReplicaLoadBalancer」を true にします

下にある「Apply」をクリックすれば PostgreSQL クラスタの再構築が行われます 完了すると以下のように外部からアクセスできるようになっています

  • kubectl get svc -l team=acid
NAME             TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
acid-test        LoadBalancer   10.107.79.204   <pending>     5432:31815/TCP   18m
acid-test-repl   LoadBalancer   10.107.39.37    <pending>     5432:30569/TCP   18m

アクセスする

パスワードはシークレットから取得します あとは公開したノードの IP とポートを使って postgres ユーザでアクセスできるか確認してみましょう

基本的な使い方はこんな感じです 今回は UI でデプロイしましたがマニフェストも UI が自動生成してくれるのでマニフェストでデプロイしたい場合でも簡単です

おまけ: ユーザの好きなパスワードは設定できない

過去に紹介した bitnami の PostgreSQL helm chart を使うとユーザのパスワードを設定できます Operator でもできないかなと思い色々試したのですがダメでした 一応試した方法を紹介します (参考)

やった方法としては

  • secret を事前に登録
  • マニフェストでユーザのロールを指定

です

  • vim secret.yaml
apiVersion: v1
data:
  password: YXNkZmdoamtsCg==
  username: cHJhZWZlY3Q=
kind: Secret
metadata:
  labels:
    application: spilo
    cluster-name: acid-gitlab
    team: acid
  name: praefect.acid-gitlab.credentials.postgresql.acid.zalan.do
  namespace: default
type: Opaque

kubectl apply -f ./secret.yaml

マニフェストをデプロイすると Operator 自動で secret を作成してしまうので事前に登録しておきました

そしてその後で Operator を使ってマニフェストからデプロイします

  • vim postgres.yaml
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  labels:
    team: acid
  name: acid-gitlab
  namespace: default
spec:
  allowedSourceRanges: null
  databases:
    praefect: praefect
  enableConnectionPooler: true
  enableMasterLoadBalancer: true
  enableReplicaLoadBalancer: true
  numberOfInstances: 1
  postgresql:
    version: '13'
  resources:
    limits:
      cpu: 500m
      memory: 500Mi
    requests:
      cpu: 100m
      memory: 100Mi
  teamId: acid
  users:
    praefect:
    - superuser
    - login
    - createrole
    - createdb
  volume:
    size: 10Gi
  • kubectl apply -f ./postgres.yaml

これで事前に作成した secret のパスワードを使って psql コマンドでログインしようとしてみましたがダメでした

あくまでも secret は外部からパスワードを確認する方法のようで PostgreSQL の内部では自動生成されたパスワードを使ってユーザの作成が行われているようです

最後に

バックアップやバージョンアップも簡単にできるので簡易 RDS みたいに使えます

UI があるのはかなり便利かなと思います

参考サイト

2021年6月11日金曜日

Gitlab の nginx-ingress を hostNetwork=true で使っていて再起動すると Address already in use になる問題を解決する方法

Gitlab の nginx-ingress を hostNetwork=true で使っていて再起動すると Address already in use になる問題を解決する方法

概要

原因は gitlab-shell が 22 番ポートを使っており、ホストの ssh ポトと被っているために nginx-ingress が再起動できなくなります

環境

  • helm v3.5.2
  • k8s v1.20.1
  • nginx-ingress v0.46.0

対応方法

gitlab-shell のポートを 22 から別のポートに変更します

--set nginx-ingress.controller.hostNetwork=true \
--set nginx-ingress.controller.service.type="" \
--set nginx-ingress.controller.kind=DaemonSet \
--set nginx-ingress.controller.service.externalTrafficPolicy="" \
--set gitlab.gitlab-shell.service.externalPort=1022 \

これで helm upgrade してあげれば再起動に成功するはずです

P.S

どうやら nginx-ingress-controller が再起動できない原因は Address already in use ではなく ConfigMap の設定がうまく反映されずエラーとなり常に再起動しているのが原因のようです

Gitlab 側のバグの可能性が高そうですが詳細な原因は不明です

参考サイト

2021年6月10日木曜日

Gitlab helm chart で複数の Praefect をデプロイして Gitaly Cluster を構成する方法

Gitlab helm chart で複数の Praefect をデプロイして Gitaly Cluster を構成する方法

概要

前回 helm chart で praefect を有効にする方法を紹介しました 今回は praefect を増やして Gitaly Cluster を構成する方法を紹介ます

環境

  • helm v3.5.2
  • k8s v1.20.1
  • nginx-ingress v0.46.0

values.yaml

praefect を複数にする=gitaly cluster を増やすということになります praefect を増やすには virtualStorage の配列部分を増やしてあげれば OK です

例えば以下のように設定します (他の設定は省略しています)

global:
  praefect:
    enabled: true
    virtualStorages:
    - name: default
      gitalyReplicas: 3
      maxUnavailable: 2
    - name: vs1
      gitalyReplicas: 3
      maxUnavailable: 2

動作確認

これでデプロイすると praefect が 2 Pod になり、gitaly Pod が 6 つになっているのが確認できます

# kubectl get pod -n gitlab | grep gitaly
gitlab-gitaly-default-0                               1/1     Running     0          68m
gitlab-gitaly-default-1                               1/1     Running     0          68m
gitlab-gitaly-default-2                               1/1     Running     0          68m
gitlab-gitaly-vs1-0                                   1/1     Running     0          13m
gitlab-gitaly-vs1-1                                   1/1     Running     0          13m
gitlab-gitaly-vs1-2                                   1/1     Running     0          13m

# kubectl get pod -n gitlab | grep praefect
gitlab-praefect-0                                     1/1     Running     0          11m
gitlab-praefect-1                                     1/1     Running     0          12m

この状態で push して一度データを gitaly に格納します そして片方の gitaly cluster を削除しても問題なく git push/pull や GUI 上でのファイル確認をすることができると思います

削除する場合は default の virtualStorage は必須なので vs1 側を削除しましょう

PVC は

gitalyReplicas で指定した分だけ PVC は作成されます

kubectl get pvc -n gitlab | grep gitaly
repo-data-gitlab-gitaly-default-0   Bound    pvc-b7bf03a9-c51d-42f7-93aa-930862fbe03c   50Gi       RWO            nfs            71m
repo-data-gitlab-gitaly-default-1   Bound    pvc-db56800f-6c38-4236-82b0-3fb375cb1fcd   50Gi       RWO            nfs            71m
repo-data-gitlab-gitaly-default-2   Bound    pvc-460bd845-c3a4-48af-acea-0f24a39fcad8   50Gi       RWO            nfs            71m
repo-data-gitlab-gitaly-vs1-0       Bound    pvc-5f80051d-b141-487a-866e-c2c04c74188c   50Gi       RWO            nfs            71m
repo-data-gitlab-gitaly-vs1-1       Bound    pvc-d5815636-c504-4335-b713-cc17af1c96a8   50Gi       RWO            nfs            71m
repo-data-gitlab-gitaly-vs1-2       Bound    pvc-4009a7f3-d199-4912-a690-ae1c3c16c6a5   50Gi       RWO            nfs            71m

GUI 上では

Gitlab の Admin area -> Overview -> Gitaly Servers でもちゃんと Praefect の数だけクラスタが確認できます

2021年6月9日水曜日

helmfile 超入門

helmfile 超入門

概要

helmfile は helm の values.yaml やパラメータ、バージョン情報などを YAML ファイルで宣言的に管理できるツールです 今回はインストール方法と簡単な使い方を紹介します

環境

  • Ubuntu 18.04
  • helm v3.5.2
  • helmfile 0.139.7

helmfile のインストール

まずは helmfile コマンドをインストールします 少しややこしいですが helmfile はコマンド名にもなっています

バイナリを 1 配置するだけで完了です docker でも動作させることができますが今回はバイナリインストールを採用します

helmfile version v0.139.7

helm diff プラグインのインストール

helmfile の一部のコマンドが helm-diff に依存しているのでインストールしておきましょう

helmfile.yaml を作成する

では helmfile.yaml を作成しましょう 本来 helm コマンドの引数になる情報を YAML ファイルに記載する感じになります

  • vim helmfile.yaml
releases:
- name: request-dumper
  namespace: default
  chart: request-dumper/request-dumper
  version: 0.1.1
  set:
  - name: replicaCount
    value: 2

helm を実行したことがあるのであればそれぞれのパラメータが何を意味しているのか何となくわかると思います

コマンドで指定していたものがファイルに定義できているのが確認できると思います

動作確認

では実行してみましょう デプロイするには apply サブコマンドを使います

  • helmfile apply

すると helmfile に記載された chart がデプロイされると思います 削除される場合は destroy サブコマンドを使います

  • helmfile destroy

values.yaml を使う方法

set ではなく values を使えば OK です

releases:
- name: gitlab
  namespace: gitlab
  chart: gitlab/gitlab
  values:
  - ./values.yaml

これで既存の values.yaml ファイルをそのまま使うことができます

helmfile sync について

デプロイするサブコマンドは apply の他 sync というサブコマンドがあります 大きく違いは以下の通りです

  • apply・・・マニフェストに差分がある場合に helm upgrade を実行する
  • sync・・・毎回 upgrade を実行するので差分がなくても revision が上がっていく

という感じの違いがあります 基本は apply を使うのが良いかなと思います

最後に

今回は簡単な方法だけ紹介しているので他にもいろいろな定義をすることができます

例えば他にも helmfile.yaml を定義してそれを include して一気にデプロイすることもできます

使用する helm が増えてきた場合にはかなり強力ツールになるかなと思います

参考サイト

2021年6月7日月曜日

Python をデコレータをクラスとして定義する方法 (Flask で使う方法もあり)

Python をデコレータをクラスとして定義する方法 (Flask で使う方法もあり)

概要

過去に Python デコレータの使い方を紹介しました 今回はデコレータをクラスとして定義する方法を紹介します

環境

  • macOS 11.4
  • Python 3.8.7

デコレータ定義

クラスとしてデコレータを定義する際にポイントは __call__ メソッドを実装する点です また引数付きのデコレータは更に内部関数を呼び出します

参考のためにクラスではなくデコレータを関数として定義する方法も紹介しています

# func の前と後に処理を書く func はデコレータを付与した関数
def first_deco(func):
    def wrapper(*args, **kwargs):
        ret = func(*args, **kwargs)
        print(" world!")
        return ret
    return wrapper

def second_deco(name):
    def _first_deco(func):
        def wrapper(*args, **kwargs):
            ret = func(*args, **kwargs)
            print(" world!" + name)
            return ret
        return wrapper
    return _first_deco

# func がデコレータを付与した関数
class FirstDeco():
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        try:
            ret = self._func(*args, **kwargs)
            print(" world!")
        except:
            raise
        return ret

class SecondDeco():
    def __init__(self, *args, **kwargs):
        self._args = args
        self._kwargs = kwargs

    def __call__(self, func):
        def wrapper_f(*args, **kwargs):
            try:
                ret = func(*args, **kwargs)
                print(" world!" + self._kwargs['name'])
            except:
                raise
            return ret
        return wrapper_f

動作確認

  • vim test_deco.py
from deco import first_deco, second_deco

from deco import FirstDeco
from deco import SecondDeco as sd

@first_deco
def first(msg):
    print(msg, end='')

@second_deco(name="hawk")
def second(msg):
    print(msg, end='')

@FirstDeco
def first_with_class(msg):
    print(msg, end='')

@sd(name="snowlog")
def second_with_class(msg):
    print(msg, end='')

first("hello")
second("hello")

first_with_class("hello")
second_with_class("hello")
  • python3 test_deco.py
hello world!
hello world!hawk
hello world!
hello world!snowlog

メリット

クラスとして定義すれば継承などが使えます オブジェクト指向として Python を書きたい人はクラスとして定義したほうがコード的にもキレイになると思います

おまけ: 前のデコレータから値を受け取る方法

class FirstDeco():
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        try:
            ret = self._func("from firstdeco !", *args, **kwargs)
        except:
            raise
        return ret

class SecondDeco():
    def __init__(self, *args, **kwargs):
        self._args = args
        self._kwargs = kwargs

    def __call__(self, func):
        def wrapper_f(from_first_deco, *args, **kwargs):
            try:
                ret = func(from_first_deco, *args, **kwargs)
            except:
                raise
            return ret
        return wrapper_f
@FirstDeco
@sd(name="snowlog")
def second_with_class(from_first_deco, msg):
    print(from_first_deco)
    print(msg, end='')

second_with_class("hello")

おまけ: Flask で使う場合には

引数を取る場合には @functools.wraps(func) を使い引数と取らない場合には functools.update_wrapper を使います

特に引数を取らない場合の書き方はあまり見慣れない書き方かなと思います 更に言うと必ず init の先頭で update_wrapper を呼び出さないと行けない点にも注意が必要です

import functools

class FirstDeco():
    def __init__(self, func):
        functools.update_wrapper(self, func)
        self._func = func

    def __call__(self, *args, **kwargs):
        try:
            ret = self._func(*args, **kwargs)
            print(" world!")
        except:
            raise
        return ret
import functools

class SecondDeco():
    def __init__(self, *args, **kwargs):
        self._args = args
        self._kwargs = kwargs

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper_f(*args, **kwargs):
            try:
                ret = func(*args, **kwargs)
                print(" world!" + self._kwargs['name'])
            except:
                raise
            return ret
        return wrapper_f

参考サイト

2021年6月6日日曜日

k8s の Operator を理解するために Operator SDK golang をとりあえず流してみた

k8s の Operator を理解するために Operator SDK golang をとりあえず流してみた

概要

k8s の Operator や CustomResource の実装をするにあたって全くイメージがなかったのでまずは Operatro SDK のチュートリアルを試してみました

環境

  • k8s v1.20.1
  • golang 1.16.3
    • operator-sdk 1.8.0
  • docker 19.03.6

準備

今回は以下の環境で実施しています

  • k8s 環境の準備
  • docker プライベートレジストリの準備

operator-sdk のインストール

まずは operator-sdk をインストールします これをインストールすることでひな形やビルドを簡単に行うことができます

  • export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac)
  • export OS=$(uname | awk ‘{print tolower($0)}’)
  • export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.8.0
  • curl -LO KaTeX parse error: Expected group after '_' at position 35: …L}/operator-sdk_̲{OS}_${ARCH}
  • gpg --keyserver keyserver.ubuntu.com --recv-keys 052996E2A20B5C7E
  • curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt
  • curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt.asc
  • gpg -u “Operator SDK (release) cncf-operator-sdk@cncf.io” --verify checksums.txt.asc
  • grep operator-sdk_KaTeX parse error: Expected group after '_' at position 5: {OS}_̲{ARCH} checksums.txt | sha256sum -c -

これで operator-sdk コマンドが使えるようになります

  • operator-sdk version

プロジェクトの作成

プロジェクトの雛形を作成します

example.com の部分は自身で準備したプライベートレジストリのドメインを設定してください

example.com でも問題なく進められるのでこのままでも OK です

以下のようなディレクトリとファイル構成で作成されます

  • tree
.
├── config
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager
│   │   ├── controller_manager_config.yaml
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── manifests
│   │   └── kustomization.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── role_binding.yaml
│   │   └── service_account.yaml
│   └── scorecard
│       ├── bases
│       │   └── config.yaml
│       ├── kustomization.yaml
│       └── patches
│           ├── basic.config.yaml
│           └── olm.config.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

API リソースの作成

次に operator の動作に必要な API の go ファイルを作成します 生成される go ファイルでプログラムすることで独自のオペレータを作成することができます

今回はチュートリアルなので github にあるサンプルを使います なお公式のチュートリアルだけだとすべてが記載されていないので注意してください

CustomResource の定義

こちらは spec のパラメータなどを指定します

コントローラの定義

実際にメインの処理を記載するコントローラを生成します

なお公式のチュートリアルは執筆時点では v1.3.0 タグの mmemcached_controller.go を使っているのですがそれで実行すると 60 行目で invalid memory address or nil pointer dereference になります

リソースファイルの生成

memcached_types.go と memcached_controller.go を編集できたらリソースファイルを生成します

  • make generate
  • make manifests

成功すると CustomResource と RBAC のマニフェストファイルが生成されます

  • less config/crd/bases/cache.example.com_memcacheds.yaml
  • less config/rbac/role.yaml

依存関係でエラーになる場合は以下を追加でインストールしてください

ビルド&プッシュ

実際に k8s 上に CustomResource をデプロイするためにイメージをビルドしてレジストリにプッシュします

冒頭プロジェクト作成時に指定した domain の部分をレジストリのドメインにしていてもプッシュ先の URL が違う場合は Makefile を修正します IMG の部分がビルドされるイメージ名になるのでここにプッシュ可能なイメージ名を指定します

  • vim Makefile
IMG ?= container-registry.your.private.repo/hawksnowlog/proj:latest

ちなみにデフォルトでは dockerhub にプッシュするようになっています あとはビルド、プッシュしましょう

  • make docker-build docker-push

もしプッシュできない場合は上記の IMG の設定を再確認してください もしくはプライベートレジストリにログインできているか確認してください もしできていない場合は docker login してからビルドしてください

デプロイ

CustomResource のイメージがレジストリにプッシュできたら実際に k8s 上に展開してみます

  • make deploy

しばらくすると以下のように CustomResource 用の Pod がデプロイされます

  • kubectl get pod -n memcached-operator-system
NAME                                                    READY   STATUS    RESTARTS   AGE
memcached-operator-controller-manager-6fb5b6d8b-bg4x5   2/2     Running   0          8m40s

認証ありのプライベートレジストリを使っている場合は

k8s からもプライベートレジストリにアクセスできる必要があります レジストリ認証情報を secret として登録しその secret 情報を CustomResource 用の Pod から使うようにします

  • kubectl create secret generic regcred --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson -n memcached-operator-system
  • kubectl edit deployment -n memcached-operator-system
    spec:
      imagePullSecrets:
      - name: regcred

もしかすると operator 作成時に imagePullSecrets を指定する方法があるのですが見つからなかったので今回は make deploy 後に手動で secrts の情報を指定しています

動作確認

これで自作の CustomResource を使ったオペレータを使って Pod などのデプロイができるようになります マニフェストは以下のファイルにあります spec の部分に size: 3 を指定しましょう

  • vim config/samples/cache_v1alpha1_memcached.yaml
apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
  name: memcached-sample
spec:
  size: 3

ポイントは kind: Memcached になっている点です これが CustomResource として自作で作成したリソースになります

デプロイして memcached の Pod が上がってくることを確認します

  • kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
# kubectl get pod
NAME                                               READY   STATUS    RESTARTS   AGE
memcached-sample-6c765df685-gsc5w                  1/1     Running   0          21s
memcached-sample-6c765df685-r9dnh                  1/1     Running   0          21s
memcached-sample-6c765df685-v8tph                  1/1     Running   0          21s
# kubectl exec pod/memcached-sample-6c765df685-gsc5w -it -- telnet localhost 11211
set name 0 0 11
hawksnowlog
STORED
quit
Connection closed by foreign host
command terminated with exit code 1

# kubectl exec pod/memcached-sample-6c765df685-gsc5w -it -- telnet localhost 11211
get name
VALUE name 0 11
hawksnowlog
END
quit
Connection closed by foreign host
command terminated with exit code 1

今回は Service などの定義がないので直接 Pod で実行していますが問題なく memcached が動作するのが確認できると思います

クリーンアップ

  • make undeploy

最後に

ポイントは

  • CustomResource を作成し API として k8s 上にデプロイする
  • その API を使って CustomResource を作成する
  • リソース作成時に好きな命令を golang で実装できる

です とりあえず今回のチュートリアルだけでもこの流れはつかめるかなと思います

実際は controller や types をプログラムして独自のオペレータを実装することになります ビルドやデプロイの流れは同じかなと思います

トラブルシューティング

memcached の Pod が CustomResource を使ってデプロイできない場合は memcached-operator-controller-manager のログを確認してみましょう

go スクリプトのビルドはできたけど nil 参照などしている場所がある場合はそこでエラーとなり CustomResource が動作していないことが確認できると思います

参考サイト