定額型パブリッククラウド
という触れ込みで先日ローンチされたCloudGarage。
そのフレーズのとおり、「1Core/ 1GB/ 50GB なクラウド VM インスタンスが3インスタンスで 1,480円/月 固定(転送量など込み)」という月額定額制のサービスメニューが用意されていて画期的。すでに趣味用途で AWS や GCP などにインスタンスをいくつか立ててる僕にはとても興味深いサービスなわけなんだけど、さらに魅力的なポイントとして、CloudGarage では「Dev Assist Program」なる、開発者向けインスタンス無償提供制度がある。
この申請に通ると、上述の「1Core/ 1GB/ 50GB なクラウド VM インスタンス x3」が1年間無料で利用できる。そして先日、めでたく僕もこの制度の適用申請が通った。ありがとうございますありがとうございます。
降ってわいたような3つのサーバーインスタンス、さてこいつで何をやろうかなということでまずは、「せっかくある3台のサーバーを活かせるようなことを」ということで、CloudGarage 上に kubernetes(k8s)クラスタを構築してみることにした。このエントリはその作業メモである。以下目次。
- 1. まずはインスタンスの作成
- 2. ログイン・ユーザーの準備
- 3. /etc/hosts の編集
- 4. マスターノードのセットアップ
- 5. コンテナ稼働ノードのセットアップ
- 6. Pod の作成、起動を試す
- 7. オマケ
- まとめ
- 参考
今回せっかくなので、ほぼ全ての作業を itamae のレシピに落としこみながら進めた。なので、このレシピを使えば誰でも簡単に k8s クラスタを CloudGarage 上に構築できるはず。間違ってるところがあったら Pull Request ください。笑
1. まずはインスタンスの作成
まずは CloudGarage のWebコンソール画面から、3つのインスタンスを作る。
- インスタンスタイプ
- 1GBタイプ
- OS/イメージ選択
- OSから選択
- CentOS 7.3 64bit
- 接続許可ポート
- 任意のポートを指定することはできないので、以下を選択する。
- 22
- 80
- 443
- SSH Key 設定
- ssh ログインできるよう、設定しておく。
- インスタンス情報
- インスタンス名
- master01 / node01 / node02
- インスタンス名
作っている過程で「インスタンスの作成に失敗しました」みたいなエラーになった・だが一覧を見ると出来ている、ということもあったので、その点は注意。
2. ログイン・ユーザーの準備
各サーバに master01
node01
などの名前で ssh できるように、手元の開発機の ~/.ssh/config
を編集しておく。
$ ssh root@master01 Last login: Mon Jun 26 13:22:52 2017 [root@master01 ~]#
ok。
とはいえ、この先の作業をずっと root でやっていくのもあれなので、作業用のユーザーを作成して sudo できるようにしておく。
以降のサーバー上の作業については、僕の書いた itamae レシピを使ってくれてもいい。GitHub - a-know/itamae-recipes-k8s: itamae recipes for build kubernetes (k8s) cluster を clone し bundle install
したあと、以下のコマンドを実行することで、ユーザー作成ができるようになってる(はず)ので、おすすめ。
$ bundle exec itamae ssh -h master01 -j base/a-know.json -u root base/user.rb $ bundle exec itamae ssh -h node01 -j base/a-know.json -u root base/user.rb $ bundle exec itamae ssh -h node02 -j base/a-know.json -u root base/user.rb
base/a-know.json
は僕の場合のものなので、同レポジトリ内にある base/user_template.json
をコピー・書き換えた上でそれを指定して実行してください。これは以降の手順でもおなじなので、以降は割愛。
$ ssh master01 Last failed login: Sat Sep 30 08:24:26 JST 2017 from xxx on ssh:notty There was 1 failed login attempt since the last successful login. [a-know@master01 ~]$ sudo su - 最終ログイン: 2017/09/30 (土) 08:45:27 JST xxxから開始日時 pts/0 [root@master01 ~]#
ok。
3. /etc/hosts
の編集
作成した各インスタンス間で、相互にホスト名でアクセスできるように /etc/hosts
に追記もする。
$ bundle exec itamae ssh -h master01 -j base/hosts.json -u root base/hosts.rb $ bundle exec itamae ssh -h node01 -j base/hosts.json -u root base/hosts.rb $ bundle exec itamae ssh -h node02 -j base/hosts.json -u root base/hosts.rb
確認する。
$ cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.0.5 master01 192.168.0.6 node01 192.168.0.7 node02
ok。
以上で3台共通のセットアップはおわり。以降、マスターノード/コンテナ稼働ノードごとの作業に移っていく。
4. マスターノードのセットアップ
ここでやるべきことは以下。
- etcd、kubernetes、flannelのインストール
- etcd の設定
/etc/etcd/etcd.conf
の編集ETCD_LISTEN_CLIENT_URLS
項目の変更ETCD_ADVERTISE_CLIENT_URLS
の変更
- flannelの設定
# etcdctl mk /atomic.io/network/config '{"Network":"172.17.0.0/16"}'
の実行- すでに追加されている場合もある?
- kubernetes の設定
- 鍵の作成と配置
/etc/kubernetes/apiserver
への設定の追記KUBE_API_ADDRESS
KUBE_API_ARGS
/etc/kubernetes/controller-manager
への設定の追記KUBE_CONTROLLER_MANAGER_ARGS
/etc/kubernetes/config
への設定の追記KUBE_MASTER
- 各コンポーネントの起動
kube-apiserver
kube-controller-manager
kube-scheduler
kube-proxy
- kubectl コマンドのための設定
~/.kube/config
の作成
とまぁ、多いっすね。ただ itamae を使えば、以下を実行するだけでできちゃう。かがくのちからってすげー!
$ bundle exec itamae ssh -h master01 -j master/config.json master/etcd.rb $ bundle exec itamae ssh -h master01 master/flanneld.rb <serviceaccount.key 用の鍵を作成し、鍵ファイルを files 以下に置いてから> $ bundle exec itamae ssh -h master01 -j master/config.json master/kubernetes.rb $ bundle exec itamae ssh -h master01 -j master/config.json master/kubectl_config.rb
鍵の作成は openssl genrsa -out /path/to/serviceaccount.key 2048
とかで作成します。
5. コンテナ稼働ノードのセットアップ
コンテナ稼働ノードのための作業は以下のようなものになる。
- flannel のインストール・設定(docker のインストール・起動)
- flannel のインストール
/etc/sysconfig/flanneld
の設定FLANNEL_ETCD_ENDPOINTS
の変更- flanneld を起動したのちに docker を起動する
- kubernetes関連の設定
itamae によるセットアップをおこなう場合は以下。
$ bundle exec itamae ssh -h node01 -j node/node_config.json node/flanneld.rb $ bundle exec itamae ssh -h node02 -j node/node_config.json node/flanneld.rb $ bundle exec itamae ssh -h node01 -j node/node_config.json node/kubernetes.rb $ bundle exec itamae ssh -h node02 -j node/node_config.json node/kubernetes.rb
以上で k8s クラスタの構築は完了。マスターノードに ssh して以下のようなコマンドを実行してみる。
$ kubectl get nodes NAME STATUS AGE node01 Ready 3m node02 Ready 9s
6. Pod の作成、起動を試す
ノードを認識しているかどうかだけじゃなく、ちゃんとコンテナを動作させることができるかどうかも確認してみる。以下のような yaml をマスターノード内に作成する。
apiVersion: v1 kind: Pod metadata: name: httpd labels: app: httpd spec: containers: - name: httpd image: httpd ports: - containerPort: 80
Apache HTTP Serverを含んだコンテナイメージを指定している。この yaml ファイルを指定して Pod を起動してみる。
$ kubectl create -f pod.yaml pod "httpd" created $ kubectl get pods NAME READY STATUS RESTARTS AGE httpd 1/1 Running 0 2m
よさそう。コンテナ稼働ノード内でも確認。
$ ssh node02 Last login: Sun Oct 1 09:45:03 2017 from xxx [a-know@node02 ~]$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bd2f5f5d2df9 httpd "httpd-foreground" About a minute ago Up About a minute k8s_httpd.74972ef5_httpd_default_8ff41316-a641-11e7-b784-fa163e02c2ac_a6103525 a0d18e000506 registry.access.redhat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" About a minute ago Up About a minute k8s_POD.a8590b41_httpd_default_8ff41316-a641-11e7-b784-fa163e02c2ac_eb268f31
よさそう。
$ kubectl get pod httpd -o yaml
コマンドの実行で、対象の Pod に関する詳細な情報が yaml 形式で取得できる。その中の podIP
がそのPodに割り当てられたIPアドレスになる。そのアドレス宛にリクエストをすると、コンテナとして起動している Apache からの応答を確認することができる。
$ curl <Pod IPアドレス> <html><body><h1>It works!</h1></body></html>
Pod の削除は $ kubectl delete pod httpd
。
$ kubectl delete pod httpd pod "httpd" deleted
7. オマケ
最後に、仕事柄、全てのノードで mackerel-agent に動いていてほしいのでそれのセットアップをする。全てのノートで動かしたいようなものの場合は Pod
ではなく DaemonSet
を指定する。
apiVersion: extensions/v1beta1 kind: DaemonSet metadata: labels: name: mackerel-agent name: mackerel-agent spec: template: metadata: labels: app: mackerel-agent spec: containers: - name: mackerel-agent image: mackerel/mackerel-agent:latest imagePullPolicy: Always env: - name: apikey value: <API Key> - name: opts value: -role=<service-name>:<role-name> - name: enable_docker_plugin value: "1" lifecycle: preStop: exec: command: ["/usr/bin/mackerel-agent", "retire", "-force"] volumeMounts: - name: docker-sock mountPath: /var/run/docker.sock - name: mackerel-id mountPath: /var/lib/mackerel-agent/ volumes: - name: docker-sock hostPath: path: /var/run/docker.sock - name: mackerel-id hostPath: path: /var/lib/mackerel-agent/
API Key などのセットを忘れずに。
で、これを指定して起動。
$ kubectl create -f mackerel-agent-daemonset.yaml daemonset "mackerel-agent" created $ kubectl get pods NAME READY STATUS RESTARTS AGE mackerel-agent-gcxgf 1/1 Running 0 47s mackerel-agent-l1b4r 1/1 Running 0 47s
Mackerel の画面上では以下のように見える。
ちなみにマスターノードには docker はインストールしてないので、こちらには普通に mackerel-agent をインストール。
$ curl -fsSL https://mackerel.io/file/script/setup-all-yum-v2.sh | MACKEREL_APIKEY='xxxx' sh This script requires superuser authority to setup Mackerel agent: ++ mktemp + gpgkey_path=/tmp/tmp.kpBsMfuLIk + curl -fsS -o /tmp/tmp.kpBsMfuLIk https://mackerel.io/file/cert/GPG-KEY-mackerel-v2 + rpm --import /tmp/tmp.kpBsMfuLIk + rm /tmp/tmp.kpBsMfuLIk + cat + yum install -y mackerel-agent <中略> インストール: mackerel-agent.x86_64 0:0.45.0-1.el7.centos 完了しました! + mackerel-agent init -apikey=xxxx + systemctl start mackerel-agent ************************************* Done! Welcome to Mackerel! *************************************
......って、この作業だけ itamae の recipe を書かずにやっちゃった。まぁいいか。。
Mackerel も5台までなら無料の範囲でモニタリング可能なので、CloudGarage との相性はよさそう。
まとめ
開発者(特にWebサービスとか作って公開したい!それを通じてサーバー運用とか勉強したい!とか思っている人)にとって「サーバーをどうするか」というのは結構悩みのタネになっていると思っていて、AWSあるやん・GCPあるやん、といっても、毎月の出費としては無視できない額のコストが掛かることを考えると、泣く泣くローカルマシン上のVMとかで自分を慰めていた人も多いんじゃないかと思う(僕は泣きながらパブリッククラウドに幾ばくかのお金を払って使っている)。ましてや、複数インスタンス + ロードバランサを使っての負荷分散をさせたいようなユースケースではなおさら。
そんななか、CloudGarage の提供してくれているサービスメニューは、まさに開発者の味方といってもいいものだと思う。今回は出てこなかったけれど、CloudGarage はロードバランサーもひとつ、無料で提供してくれる。
この「もれなく3台」という特長をいかした様々な遊びを、今後もやっていきたい。ということで、次は何をしよっかな!