こんにちは、サイオステクノロジー技術部 武井です。今回は分散KVSであるetcdを世界最速で試しましたので、その方法をご紹介します。
etcdとは?
OSSの分散KVSです。単純なkey-Value形式のデータを保存することができます。アーキテクチャーも単純で、構築もそれほど難しくはありません。詳細は以下のURLを御覧ください。
用途は、アプリケーションなどの設定ファイルを分散して保存したいときに使います。ローカルのファイルに書くと、そのファイルが失われた場合設定ファイル消えちゃいますし、ではMySQLとかCassandraなどのデータベースでもレプリケーションとかすれば分散して設定を保存できますが、たかだかKey-Value形式の設定保存するためにデータベースって大げさな気がします。
そこでetcdの登場なのですが、etcdは本当に単純なKey-Value形式の分散データストアです。キーを指定してデータを貯めるだけです。導入も簡単だし、アプリケーションの設定ファイルのような、単純なKey-Value形式のデータストアならモッテコイです。
Kubernetesの設定を保存するために利用されているのが有名かと思います。
試してみたいけれども、、、
導入が簡単とは言っても、やっぱりインストールとか面倒ですよね。なんか、サクッと試す方法ないかなと思ってGitHub見てたらDockerを使ったインストール方法がありました(´;ω;`)ブワッ
https://github.com/etcd-io/etcd/releases
わーい(*^_^*)
きっかけ
現在、ワタクシ、Kubernetes The Hard Wayというのをやっております。これは、昨今、Azure Kubernetes ServiceなどのManagedなKubernetesが多く、導入の敷居も非常に下がっておりますが、Kubernetesへの理解を深めるために、わざわざ難しい方法でインスコしましょうというのがKubernetes The Hard Wayです。
https://github.com/kelseyhightower/kubernetes-the-hard-way
その過程の中でetcdのインストールが出てきます。Kubernetesはその設定を保存するためにetcdを使っています。etcdへの理解を深めたかったので実際に設定ファイルをシコシコいじりながら試してみようと思っていたのですが、仮想マシンとか何個も立ててクラスター組むのはなぁと思っていたところに、公式のGitHubでDockerによるインストール方法を見つけました。これならサクッとインスコして試せるはずと思いまして、実際に試してみた次第でございます。
やってみよう
etcdのDockerコンテナを2台立てて分散してデータが保存されるのを試してみたいと思います。以下のコマンドを打つだけで環境は出来上がってしまいます。
$ docker network create etcd-network --subnet=172.16.0.0/24 --ip-range=172.16.0.0/24 $ rm -rf /tmp/etcd-data1.tmp && mkdir -p /tmp/etcd-data1.tmp && \ docker run -d \ --network etcd-network \ --ip 172.16.0.4 \ -p 2379:2379 \ -p 2380:2380 \ --mount type=bind,source=/tmp/etcd-data1.tmp,destination=/etcd-data \ --name etcd1 \ gcr.io/etcd-development/etcd:v3.4.5 \ /usr/local/bin/etcd \ --name etcd1 \ --data-dir /etcd-data \ --listen-client-urls https://0.0.0.0:2379 \ --advertise-client-urls https://0.0.0.0:2379 \ --listen-peer-urls https://172.16.0.4:2380 \ --initial-advertise-peer-urls https://172.16.0.4:2380 \ --initial-cluster etcd1=https://172.16.0.4:2380,etcd2=https://172.16.0.5:2382 \ --initial-cluster-token tkn \ --initial-cluster-state new $ rm -rf /tmp/etcd-data2.tmp && mkdir -p /tmp/etcd-data2.tmp && \ docker run -d \ --network etcd-network \ --ip 172.16.0.5 \ -p 2381:2381 \ -p 2382:2382 \ --mount type=bind,source=/tmp/etcd-data2.tmp,destination=/etcd-data \ --name etcd2 \ gcr.io/etcd-development/etcd:v3.4.5 \ /usr/local/bin/etcd \ --name etcd2 \ --data-dir /etcd-data \ --listen-client-urls https://0.0.0.0:2381 \ --advertise-client-urls https://0.0.0.0:2381 \ --listen-peer-urls https://172.16.0.5:2382 \ --initial-advertise-peer-urls https://172.16.0.5:2382 \ --initial-cluster etcd1=https://172.16.0.4:2380,etcd2=https://172.16.0.5:2382 \ --initial-cluster-token tkn \ --initial-cluster-state new
では上記のコマンドの詳細な説明をしたいと思います。
$ docker network create etcd-network --subnet=172.16.0.0/24 --ip-range=172.16.0.0/24
まずこちらですが、Dockerのネットワークを作っています。etcdは、後ほど説明しますが、接続を許可するクライアントや、登録したデータをレプリケーションするためのetcd同士の通信の設定にIPアドレスが必要になります。なので、あらかじめDockerコンテナに固定のIPアドレスを割り振ることができるようDockerのネットワークを作成して、Dockerコンテナ作成時にそのネットワークに割当てます。上記の設定は、172.16.0.0/24のサブネットのネットワークを作成して、Dockerコンテナに割り当てることができるIPアドレスのレンジが同じく172.16.0.0/24ですよという意味です。
$ rm -rf /tmp/etcd-data1.tmp && mkdir -p /tmp/etcd-data1.tmp && \
ここからは1台目と2台目の共通の設定です。etcdのデータを永続化するために、コンテナの中ではなくホスト上にデータを保存します。後ほどDockerコンテナからホスト上のディレクトリをマウントする設定が出てくるのですが、これはそのディレクトリの削除と作成です。最初に削除しているのは、以前のDockerコンテナ作成時に生成されたゴミデータを消すためです。
docker run -d \ --network etcd-network \ --ip 172.16.0.5 \
Dockerコンテナをデーモンで起動し、先程作成したetcd-networkに所属させ、そして固定のIPアドレスを割り当てます。IPアドレスは1台目と2台目で異なるものを割り当てます。
-p 2379:2379 \ -p 2380:2380 \
ホスト上のポートとコンテナ上のポートをマッピングします。2379はetcdのクライアントからの通信用、2380はクラスタメンバーからの通信用です。今回、同じホスト上に2台のetcdを立てるので、2台めは上記と異なるポート番号にします。2380は、コンテナ同士の通信用なので、いらないかもしれません。
--mount type=bind,source=/tmp/etcd-data1.tmp,destination=/etcd-data \
コンテナ上の/etc-dataディレクトリをホスト上の/tmp/etcd-data1.tmpディレクトリにマウントさせるための設定です。コンテナを消しちゃうとデータが消えてしまうので、ホスト上にデータを永続化しています。でも今回は検証用なので特に不要かも(´・ω・`)
--name etcd1 \ gcr.io/etcd-development/etcd:v3.4.5 \
作成するコンテナ名をコンテナのイメージ名を指定しています。
/usr/local/bin/etcd \ --name etcd1 \
ここからはいよいよetcdの起動及びパラメータの指定です。とりあえずetcdデーモンを起動して、その名前をetcd1とします。2台目はetcd2としています。
--data-dir /etcd-data \
etcdのデータを保存するディレクトリを指定します。先程の設定によりこのディレクトリはホスト上のディレクトリにマウントされていますので、実際のデータはホスト上に永続化されています。
--listen-client-urls https://0.0.0.0:2379 \
etcdからのクライントからの接続を許可するIPアドレスとポートを指定します。全てのIPアドレスを許可する場合は、0.0.0.0を指定します。例えば192.168.0.1からのみの接続を許可したい場合は、https://192.168.0.1:2379と指定します。
--advertise-client-urls https://0.0.0.0:2379 \
他のクライアントやクラスタメンバーに通知する接続許可IPアドレスとポートです。こちらですが、etcdctl member listというコマンドを打つと、他のクラスタメンバーの情報が表示されます。そのコマンド実行時に上記のIPアドレスが表示されます。それをみて、このクラスタメンバーは0.0.0.0からの接続を許可しているのねと知ることになるのだと思います。ちなみに、この値が適当な値(例えば存在しないIPアドレス)にしても特に動作に問題はなさそうでした。あくまでも他のクラスタメンバーへの通知用のようです。
--listen-peer-urls https://172.16.0.4:2380 \
これは、クラスタメンバー間の通信用(クラスタメンバー間のデータの分散保存)に使うURLです。ここではetcd1の–listen-peer-urlsをhttps://172.16.0.4:2380と指定していますが、他のクラスタメンバーがetcd1と通信するためには、このURLを指定しなければなりません。
--initial-advertise-peer-urls https://172.16.0.4:2380 \
他のクラスタメンバーに通知する、クラスタメンバー間の接続URLです。これも先程と同様etcdctl member listというコマンドを打つと表示される情報です。ここで表示される情報をもとに、他のクラスタメンバーへの接続先を定義します。ちなみにこのURLのホスト名の部分には、IPアドレスだけではなく、名前解決できるホスト名を指定できます。今回の例で言えば、https://etcd1:2380という値を指定できます。ここで指定した値は、後ほど、紹介するクラスター接続先の設定に含まれていなければなりません。
--initial-cluster etcd1=https://172.16.0.4:2380,etcd2=https://172.16.0.5:2382 \
クラスター接続先の設定になります。ここには、全てのクラスターメンバーの接続先URL(–listen-peer-urlsもしくは–initial-advertise-peer-urlsで指定した値)を、「クラスター名=クラスターメンバーの接続先URL」の形式で指定します。
--initial-cluster-token tkn \
クラスターメンバー間の通信に使うためのトークンです。全てのクラスターで同じものを設定します。
--initial-cluster-state new
クラスターを新規構築する場合にnewを指定します。
テストしましょう
では、クラスターがちゃんと構築できているか確認してみます。
etcd1の方にデータを入れてみます。専用のAPIが提供されていますので、それを実行します。
$ curl -X POST -d '{"key": "hoge","value": "fuga"}' https://localhost:2379/v3/kv/put {"header":{"cluster_id":"1446266757005371193","member_id":"11570564270813865852","revision":"2","raft_term":"5"}}
etcd1でデータが登録されているか確認してみます。
$ curl -L https://localhost:2379/v3/kv/range -X POST -d '{"key": "hoge"}' {"header":{"cluster_id":"1446266757005371193","member_id":"11570564270813865852","revision":"2","raft_term":"5"},"kvs":[{"key":"hoge","create_revision":"2","mod_revision":"2","version":"1","value":"fuga"}],"count":"1"}
おおヮ(゚д゚)ォ!登録されています。
次はetcd2です。
$ curl -L https://localhost:2381/v3/kv/range -X POST -d '{"key": "hoge"}' {"header":{"cluster_id":"1446266757005371193","member_id":"14397775499308048393","revision":"2","raft_term":"5"},"kvs":[{"key":"hoge","create_revision":"2","mod_revision":"2","version":"1","value":"fuga"}],"count":"1"}
おおヮ(゚д゚)ォ!登録されています。
ちゃんと分散されていることが確認できました(*^_^*)
さいごに
サクッとetcdを試したいときにはこの方法、とってもいいと思います。ではステキなetcdライフを送ってください。No etcd, No Life!!