クラウドで安く自分のkubernetesを持ちたい

[2020/02/29 gistのリンクが切れと誤記修正]

よく聞く名前になったkubernetesを勉強するために安い環境が欲しいと思ったときに、AWSで作ると意外と高い。本記事の構成で作ったところ**$8/月程度**で自分のkubernetesを持つことが出来た。

Raspberry piで作るという方法もあるけど、CPUがARMベースになるのでAMD64ベースで作られている一般的なDockerイメージが使えないという不便があるからちょっと微妙。

Intel CPUが使えるRaspberry piみたいなやつでUP boardがあって、これを5台とNWスイッチと電源を用意すると9万円ぐらいで作れたしちゃんと動いた。常時起動させておいても安定していたし、小さくて音も靜かだから置き場所にも困らなかった。

kubernetesの障害試験でLANケーブル抜いたり、いきなり電源断してみたりいろいろ試験もしたし、LEDがいっぱいチカチカしてたり見てて楽しかったけど、外出先からちょっと動きを確認したいときは不便だった。(外部アクセス設定すれば良いけど、固定IPの回線でもなかったし。)

そんなわけで、やっぱりどこからでも自由に構成変更できるクラウドが便利だなってことで、いろいろ考えてGCPのGKEが一番安く出来ると思ったので構築してみた。

今回は安さが大事なので可用性と耐障害性は二の次三の次なので、商用サービスでこの構成はしない方が良い。

構成はこんな感じで、GEKのポッドへのアクセスはロードバランサーではなくVMインスタンスにインストールしたtraefikのOSS版を使うことにした。

なぜロードバランサーを使わないかというと、GCPはUSの特定リージョンのみf1-microを無料で使うことが出来る(2020/02/01現在)ため、ロードバランサー代をケチることができる。

さらにtraefikはすごいプロダクトで、Let's encryptの証明書取得から更新までを自動でおこなってくれて、お手軽にHTTPS通信が出来てしまう便利な機能もあります。そこで今回はGoogle Cloud DNSをつかってワイルドカード証明書を取得します。もしので自分のドメインを持っているない場合は、設定ファイルを一部書き換えれば出来ると思います。

あらすじ

  1. GKE用のVPCの作成
  2. GKEの作成
  3. traefikのインスタンス作成
  4. traefikの設定
  5. Kubernetes Dashboardのデプロイ(アプリのサンプルとして)
  6. おまけ(CLIコマンドで設定する場合)

注: USリージョンでのみ安く利用できるので、間違って日本リージョンで作るとちょっと高くなります。

注: GCPとk8sの基本的な使い方などの説明はしません。探せばいっぱいあるので。

1. GKE用のVPCの作成

GKEでVPCネイティブを有効にしてVMインスタンスなどとの接続を簡易化させるため、POD数が増えるとIPアドレスの使用も増えるためGKE用にのVPCネットワークを作ります。

名前説明はわかりやすい適当な値で、サブネットの作成モードはお手軽に自動で。

あとはGKEのVMインスタンスにSSH接続したければ、ファイヤーウォールルールtcp:22を許可するようにチェックを入れておけば良いと思います。

※traefikをインストールするVMインスタンスにはSSHアクセスする必要があるので、ここでチェックを入れなかった場合は自分でファイアウォールのルールを作ってください。

2. GKEの作成

GKEを作成するときに安く使う時の設定するポイントは下記の3点。

  1. マシンの構成を共有コアプリエンプティブル ノードを有効化を選ぶ
  2. ネットワーキングでVPC ネイティブを有効にするにした上で、先で作成したVPCを選ぶ
  3. セキュリティでクライアント証明書を発行するにチェックを入れる(GKE作成後に設定変更はできず、クライアント証明書が有効になっていないとtraefikが認証されずにGKEにアクセスできない)
  • GKEの作成画面からノード設定のその他の設定項目を開き、画像のように3カ所の設定を変更します。(1.の設定をする)

    マシンタイプはe2-mediumを選ぶことをおすすめします。

    それ以下のマシンタイプを選ぶとメモリが少ないため、PODをホストするためにインスタンス数が増えるのでコスト削減としては意味があまりないです。

    それ以外の項目はお好みで。(Poolの設定を作成後の構成は一部は変更できる程度なので、設定を変えたければPoolを作り直すことになります。)

  • GKEの設定に2.3.の設定を入れます。

    くれぐれもクライアント証明書を発行するにチェックを入れるのを忘れないようにしてください。

    デフォルトは無効になっており、有効化を忘れるとGKEを作り直すことになります。

    それ以外の項目はお好みで。

    (GKEの設定も作成後の構成変更はあまり出来ないので、変えたかったら作り直す程度の気持ちで。)

最終的に設定を終えて、作成ボタンを押すと5分程度でGKEが使えるようになります。

kubectlでGKEに接続する方法はローカルにインストールする方法とcloud shellを使う方法がありますが、個人的にはインストールも要らずブラウザから使えるcloud shellの方が便利かなと思ってます。

3. traefikのインスタンス作成

traefikのインスタンス作成するときのポイントは下記の3点

  1. 無料利用が可能なリージョンかつGKEと同じVPCにする
  2. プリエンプティブは有効にしない!(有効にすると消えちゃう!)
  3. traefikの設定は別のディスクに保存する(絶対消さないって言う人はOSと同じでも良いけど。)
  • リージョンをGKEと同じにした上で、マシン構成を N1f1-micro にする。ファイアウォールの設定で HTTPHTTPS トラフィックを許可する

  • ディスクのタブに切り替えてtraefikの設定を保存する外部ディスクを設定する。

    (ディスクサイズはいくつでも良いが10GBが最小値)

  • ネットワークタブに切り替えて、ネットワークタグにSSHを許可するタグを付け(図の場合はallow-ssh)、ネットワークを最初に作ったGKE用のVPCを選択する。サブネット等はそのまま。

あとは作成を押して起動するのを待つ。

4. traefikの設定

traefik用のVMインスタンスが起動したら、以下の5つの設定をおこなう。

  1. 設定保存用のディスクのフォーマットとマウント
  2. traefikとツールのインストール
  3. GKEにtraefik連携の設定
  4. 証明書取得のDNS認証時にCloud DNSにアクセスするためのCredentialの取得(ドメイン認証しない場合は不要)
  5. traefikの設定
  • 設定保存用のディスクをフォーマットしてfstabに登録する

    $ sudo mkfs.ext4 /dev/disk/by-id/google-traefik-pv
    $ sudo mkdir -p /traefik-pv
    $ sudo mount /dev/disk/by-id/google-traefik-pv /traefik-pv
    $ sudo mkdir -p /traefik-pv/log
    $ echo '/dev/disk/by-id/google-traefik-pv /traefik-pv ext4 defaults 0 2' | sudo tee -a /etc/fstab
  • traefikをダウンロードして配置とツール(apache2-utils)のインストール

    # Install apache-utils and setcap
    $ sudo apt-get update
    $ sudo apt-get upgrade -y
    $ sudo apt-get install -y apache2-utils libcap2-bin
    
    # Install traefk
    $ curl -L https://github.com/containous/traefik/releases/download/v2.1.4/traefik_v2.1.4_linux_amd64.tar.gz | tar zxf -
    $ sudo mv traefik /usr/local/bin/
    $ sudo useradd -s /sbin/nologin traefik
    $ sudo chown -R traefik:traefik /traefik-pv
    $ sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/traefik
    $ sudo tee /etc/systemd/system/traefik.service <<EOF >/dev/null  
    [Unit]
    Description=traefik 
    After=network-online.target
    Wants=network-online.target systemd-networkd-wait-online.service
    
    [Service]
    Restart=on-abnormal
    
    User=traefik
    Group=traefik
    
    WorkingDirectory=/traefik-pv
    Environment=GOOGLE_APPLICATION_CREDENTIALS=/traefik-pv/secret.json
    ExecStart=/usr/local/bin/traefik --configfile=/traefik-pv/traefik.toml
    
    [Install]
    WantedBy=multi-user.target
    EOF
    
    $ sudo systemctl daemon-reload
    
    $ sudo tee /etc/logrotate.d/traefik <<EOF >/dev/null
    /traefik-pv/log/log.txt {
      daily
      rotate 30
      missingok
      notifempty
      copytruncate
      dateext
      dateformat %Y-%m-%d
    }
    
    /traefik-pv/log/traefik.log {
      daily
      rotate 30
      missingok
      notifempty
      copytruncate
      dateext
      dateformat %Y-%m-%d
    }
    EOF
    
    $ sudo /usr/sbin/logrotate /etc/logrotate.conf
  • cloud shellにtraefik-config.yamlファイルをGistからダウンロードします。

    ここではお手軽にKubernetes クラスタの画面より接続ボタンよりCloud shellを起動して、Enterキーを押せばGKEにコマンド実行できる環境が立ち上がります。

    以下のコマンドを実行して設定をGKEに反映します。

    $ kubectl apply -f traefik-config.yaml

    次の設定に必要になるのでTokenをメモしておきます。

    $ kubectl describe secret $(kubectl get secret | grep traefik-ingress-controller-token | awk '{print $1}')
  • ワイルドカード署名書を取得するためのDNS認証をおこないます。そのためにCloud DNSへtraefikが認証コードを書き込める必要があり、GCPからCredentialを取得します。

    今回は手抜きでCloud DNSの管理者権限を持ったCredentialとしますが、出来ればもっと権限は絞った方が良いと思います。

    1. IAMと管理からサービスアカウントの作成をおこないます。サービスアカウント名はわりやすい名前を付けてください。
    2. 役割にはDNS管理者を設定します。traefikが認証コードのTXTレコードを書き込める必要があるので、ここでは管理者にしています。
    3. キーを作成からJSONファルを忘れずに取得して、/traefik-pv/secret.jsonとして保存してください。
  • GKEとLet's encryptが設定済みのtraefik.tomltraefik.route.tomlの2ファイルをGistから/traefik-pvにダウンロードします。

    ダウンロード後に各ファイルで以下の箇所をそれぞれの環境に合わせて書き換えてください。

    • traefik.toml

      • 77行目 : endpoint に GKEのクラスタ詳細から エンドポイント のIPアドレスを設定します。
      • 78行目 : 先ほどメモしたTokenを設定します。
      • 78行目 : endpoint に GKEのクラスタ詳細から エンドポイント にあるクラスタの証明書を表示から証明書をコピーし、 /traefik-pv/ca.crtに保存します。
    • traefik.route.toml

      • 4行目、10行目、11行目にGKEで使用するドメインを設定します。(このドメインはtraefikの管理画面のURLにもなります)
      • 17行目: traefikの管理画面にログインするためのBASIC認証のIDとPWを設定します。(htpasswd -nb user passwordのコマンドで生成した値)
  • traefikの起動

    $ sudo systemctl start traefik
    $ sudo systemctl enable traefik

    設定できていれば、https://your-domain.example.com/dashboardでこんな感じの管理画面が表示されるはずです。

5. Kubernetes Dashboardのデプロイ(アプリのサンプルとして)

Kubernetes Dashboardのデプロイでは以下の2つの設定をおこなう。

  1. GKEにKubernetes Dashboardをデプロイ
  2. traefikにKubernetes Dashboardへのルーティングの設定
  • Kubernetes Dashboardのデプロイしますが、公式サイトに記載されているrecommended.yamlではdashboard側でHTTPSになっています。

    しかし今回はtraefikでSSLオフロードしたいためdashboard側はHTTPとなるようにalternative.yamlとして、下記のコマンドを実行します。

    kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc5/aio/deploy/alternative.yaml
  • cloud shellにtraefik-k8s-dashboard.yamlファイルをGistからダウンロードします。

    traefik-k8s-dashboard.yamlの10行目にKubernetes Dashboardにアクセスするためのドメインに書き換えてください。(先ほど設定したCloud DNSで取得できる範囲で)

    次に下記のコマンドでGKEにルーティングの設定を登録します。

    kubectl apply -f traefik-k8s-dashboard.yaml

    次に下記のコマンドでKubernetes Dashboardのログイン画面で下記のコマンドで取得したTokenを入力するとログインできます。

    kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

おまけ

コマンドラインから作る

  1. GKE用のVPCをつくる。projectを書き換えてください。 k8sは今回作成するVPC名なので違う名前が良ければ変えてください。
    gcloud compute --project="your-project" networks create k8s --description="for gke" --subnet-mode=auto
  2. GKE 作成する。projectnetworksubnetworkを書き換えてください。違うリージョンやゾーンの場合は、zoneも変えてください。
    gcloud beta container --project "your-project" \
        clusters create "your-first-cluster-1" \
            --zone "us-central1-a" \
            --no-enable-basic-auth \
            --cluster-version "1.15.8-gke.3" \
            --machine-type "e2-medium" \
            --image-type "COS"  \
            --disk-type "pd-standard" \
            --disk-size "30" \
            --scopes "https://www.googleapis.com/auth/devstorage.read_only",\
                     "https://www.googleapis.com/auth/logging.write",\
                     "https://www.googleapis.com/auth/monitoring",\
                     "https://www.googleapis.com/auth/servicecontrol",\
                     "https://www.googleapis.com/auth/service.management.readonly",\
                     "https://www.googleapis.com/auth/trace.append" \
            --num-nodes "1"  \
            --enable-stackdriver-kubernetes 
            --enable-ip-alias  \
            --network "projects/your-project/global/networks/your-network-name"  \
            --subnetwork "projects/your-project/regions/us-central1/subnetworks/your-subnet-name"  \
            --default-max-pods-per-node "110"  \
            --addons HorizontalPodAutoscaling,HttpLoadBalancing  \
            --enable-autoupgrade  \
            --enable-autorepair
  3. traefkのインスタンス作成。projectsubnetworkservice-accountcreate-diskを書き換えてください。違うリージョンやゾーンの場合は、zoneも変えてください、
gcloud beta compute --project="your-project" \
    instances create traefik \
        --zone=us-central1-a \
        --machine-type=f1-micro \
        --subnet="your-subnet-name" \
        --network-tier=PREMIUM \
        --maintenance-policy=MIGRATE \
        --service-account=your-service-account@project.gserviceaccount.com \
        --scopes=https://www.googleapis.com/auth/devstorage.read_only,\
                 https://www.googleapis.com/auth/logging.write,\
                 https://www.googleapis.com/auth/monitoring.write,\
                 https://www.googleapis.com/auth/servicecontrol,\
                 https://www.googleapis.com/auth/service.management.readonly,\
                 https://www.googleapis.com/auth/trace.append \
        --tags=allow-ssh,http-server,https-server \
        --image=debian-9-stretch-v20200210 \
        --image-project=debian-cloud \
        --boot-disk-size=10GB \
        --boot-disk-type=pd-standard \
        --boot-disk-device-name=traefik \
        --create-disk=mode=rw,size=10,type=projects/your-project/zones/us-central1-a/diskTypes/pd-standard,name=traefik-pv,device-name=traefik-pv \
        --reservation-affinity=any