kun432's blog

技術ネタ、読書記録、など。2015年から人生をやり直し中です。

Kubernetes The Hard Way をVagrantでやってみた①

今回はAlexaと全然関係ない話です。いろいろあってk8sをやっています。で、とりあえずやってみたものの、抽象化度合いが深すぎて全く理解できていない感を拭えないので、これをやってみようという話です。

オリジナルはGCPを使うのですが、もうちょっと手触り感ある感じでやりたい、ということで、以下を参考に進めたいと思います。

なおVagrant版のgithubはこちらです。サラッと流すのではなく、中身も読んで行きたいと思います。

多分1回では終わらないのとしっかり理解を深めるのが目的なので、複数回に分けて説明等を追加しながらやっていきたいと思います。


Vagrantの準備

Vagrantが入ってない方はインストールしてください。Macならhomebrew caskでVagrantVirtualbox両方入れてしまうのがかんたんでおすすめです。

$ brew cask install vagrant virtualbox

Vagrantプラグインも追加しましょう。vagrant-vbguestを入れておくと、VirtualboxのGuestAdditionをバージョンに合わせて入れてくれるのでおすすめです。

$ vagrant plugin install vagrant-vbguest

もう一つプラグインを追加。ローカルからvagrantにscpを行うステップがあるので、vagrant-scpプラグインを追加しておきます。

$ vagrant plugin install vagrant-scp

Vagrant版のVagrantfileを見ると、Ubuntu18.04LTSを使うようです。何故か私の環境ではboxの展開にコケてたので、手動でboxは先に追加してます。

$ vagrant box add ubuntu/bionic64

レポジトリをクローン

$ git clone https://github.com/kenfdev/kubernetes-the-hard-way-vagrant.git
$ cd kubernetes-the-hard-way-vagrant

構築する環境

Vagrant仮想マシンを起動します。

$ vagrant up

合計7台の仮想マシンが起動します(Macbook Pro Late2016 15インチのフルスペックでもかなり時間かかります。)。Vagrantfileの中身を追いかけるとこんな感じに見えます。

f:id:kun432:20200215231337p:plain

  • 10.240.0.0/24に LB ✕ 1、master ✕ 3、worker ✕ 3が作成される
  • LBはHAProxyをつかってmasterのapiserverの負荷分散を行う(scripts/bootstrap/vagrant-setup-haproxy.sh)
  • それぞれのworkerのインタフェースに対して、10.200.X.0/24のネットワークへのルーティングを設定する。(scripts/bootstrap/vagrant-setup-routes.sh)。多分これがpodのネットワーク。
  • master、workerはhostsファイルで名前解決(scripts/bootstrap/vagrant-hosts-file.sh)

はい、これで準備ができました。では順次やっていきます。

Prerequisites

特にやることはないのでスキップ

Installing the Client Tools

クライアント側のツールをインストールします。cfsslとcfssljsonはhomebrewを使いました。

$ brew install cfssl
$ cfssl version
Version: 1.4.1
Runtime: go1.13.4
$ cfssljson --version
Version: 1.4.1
Runtime: go1.13.4

cfsslとかcfssljson初めて知ったけど、SSL証明書に必要な秘密鍵CSRjsonで作れるというものらしい。これは便利ですね。

aligach.net

あと、kubectlはもともとdocker for macが入っていてkubectkも入っているのでそれを使ってみようと思います。

$ kubectl version --client
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}

Provisioning Compute Resources

特にやることはないのでスキップ

Provisioning the CA and Generating TLS Certificates

k8sでは各種コンポーネントで証明書が必要になりますので、まず最初に公開鍵基盤として、認証局の証明書と秘密鍵を作成します。スクリプトの中では、設定ファイルとCSRを作成して、それをもとに認証局の証明書と秘密鍵を生成します。

$ scripts/k8s-the-hard-way/0400-certificate-authority.sh

これで、

  • ca-config.json
  • ca-key.pem
  • ca.pem

ができます。

次にクライアント・サーバ証明書を作成します。これらはk8sの各コンポーネントで使用します。

まず、k8sのadminユーザ用のクライアント証明書を作成します。ここで最初に作成した認証局の署名が入った証明書が作成されます。

$ scripts/k8s-the-hard-way/0410-admin-client-certificate.sh

これで、

  • admin-key.pem
  • admin.pem

ができます。

次にkubeletのクライアント証明書。kubeletはworker nodeで動作するエージェントで、各ノード内でpodの起動管理を行います。k8sにはNode Authorizerという権限管理の仕組みがあり、ノード、すなわちkubeletからのAPIリクエストをそのノードに割当てられたpodが必要とするリソースに限定します。ここでクライアント証明書が必要となります。

$ scripts/k8s-the-hard-way/0411-kubelet-client-certificates.sh

これで、各ノード用の証明書と秘密鍵が作成されます。

  • worker-0-key.pem
  • worker-0.pem
  • worker-1-key.pem
  • worker-1.pem
  • worker-2-key.pem
  • worker-2.pem

次にkube-controller-manager用の証明書と秘密鍵を作成します。controller-managerはmaster上で、各種controllerを実行管理します。具体的には、ノードダウン時の通知や対応を行うnode controllerや、レプリケーションを行うreplication controllerなどです。

$ scripts/k8s-the-hard-way/0412-controller-manager-client-certfiicate.sh

kube-controller-manager用の証明書と秘密鍵が作成されます。

  • kube-controller-manager-key.pem
  • kube-controller-manager.pem

次にkube-proxy用のクライアント証明書・秘密鍵を作成します。kube-proxyは各worker上で、serviceとpod間のルーティングを行います。

$ scripts/k8s-the-hard-way/0413-kube-proxy-client-certificate.sh

以下が作成されます。

  • kube-proxy-key.pem
  • kube-proxy.pem

次。kube-scheduler用のクライアント証明書・秘密鍵を作成します。kube-schedulerはmaster上で動作し、podのノードへの割当を行うスケジューラです。

$ scripts/k8s-the-hard-way/0414-scheduler-client-certificate.sh

以下が作成されます。

  • kube-scheduler-key.pem
  • kube-scheduler.pem

次に、kube-api-server用のサーバ証明書秘密鍵を作成します。kube-api-serverがkubernetesをコントロールするためのAPIフロントエンドになります。このときホスト名は以下となっています。

この中で、10.32.0.1というのがどこから来ているかわからなかったのですが、ちゃんとオリジナルには書いてありました。オリジナルのホスト名が増えてたのでそこも少し修正。

$ scripts/k8s-the-hard-way/0415-kubernetes-api-server-certificate.sh

以下ができます。

最後にServiceAccount用のキーペアを作成します。ServiceAccountはアプリケーション内からAPIを叩く際の権限や認可を行う仕組み。GCPだとそのままだし、AWSだとロールみたいなものだと思えばよいのかなと思ってます。

$ scripts/k8s-the-hard-way/0420-service-account-key-pair.sh

以下ができます。

  • service-account-key.pem
  • service-account.pem

これで一通り、証明書と秘密鍵が生成されました。これをmasterとworkerに配置していきます。このときvagrant-scpプラグインが必要となります。

  • 各workerには以下を配置します。
    • ca.pem
    • worker-?-key.pem
    • worker-?.pem
  • masterには以下を配置します。
$ scripts/k8s-the-hard-way/0430-distribute-certificates.sh

kube-proxy、kube-controller-manager、kube-scheduler、kubeletについては次項で設置します。

Generating Kubernetes Configuration Files for Authentication

kubenetesの設定ファイルを作成します。kube-proxy、kube-controller-manager、kube-scheduler、kubeletの各クライアントとadminユーザの設定を行うことにより、kube-api-serverに接続ができるようになります。

概ねスクリプトの中身はこんな感じのことをやってるようです。

  • kube-api-serverのIPアドレスは、worker側設定ファイルではlb-0の10.240.0.40を指定(HAのため)、master側設定ファイルでは127.0.0.1を指定します。
  • kubectl configコマンドを使ってクラスタ、認証情報、コンテキストをセットしたworker-?.kubeconfigを生成します。

ではやっていきましょう。まずworker側。

kubelet。

$ scripts/k8s-the-hard-way/0500-kubelet-kubeconfig.sh

以下ができます。

  • worker-0.kubeconfig
  • worker-1.kubeconfig
  • worker-2.kubeconfig

次にkube-proxy。

$ scripts/k8s-the-hard-way/0501-kube-proxy-kubeconfig.sh
  • kubelet.kubeconfig

master側です。

kube-controller-manager。

$ scripts/k8s-the-hard-way/0502-kube-controller-manager-kubeconfig.sh

kube-scheduler。

$ scripts/k8s-the-hard-way/0503-kube-scheduler-kubeconfig.sh

adminユーザ。

$ scripts/k8s-the-hard-way/0504-admin-kubeconfig.sh

これで以下が生成されます。

  • kube-proxy.kubeconfig
  • kube-controller-manager.kubeconfig
  • kube-scheduler.kubeconfig
  • admin.kubeconfig

最後にこれを配置していきます。

  • worker
    • worker-?.kubeconfig
    • kube-proxy.kubeconfig
  • master
    • kube-controller-manager.kubeconfig
    • kube-scheduler.kubeconfig
    • admin.kubeconfig
$ scripts/k8s-the-hard-way/0510-distribute-kubeconfig.sh

Generating the Data Encryption Config and Key

kubernetesは様々なデータを保持しますが、これらを暗号化することができます(Kubernetes Secrets)。そこで暗号化の設定と鍵の作成を行います。

スクリプト内では以下が行われます。

  • 暗号化の鍵を作成
  • 暗号化設定を生成し、鍵を埋め込む
$ scripts/k8s-the-hard-way/0600-encryption-config.sh

encryption-config.yamlが作成されますので、これをmasterに配布します。masterに配布するのはetcdが暗号化データを管理するためです。

$ scripts/k8s-the-hard-way/0610-distribute-encryption-config.sh

今日はここまで。準備段階だけでも結構かかった気がしますが、引き続き。