nabeo がピーしているブログ (仮)

どーも、nabeop です

k8s クラスタを気軽に遊べる環境を作っている

k8s のマネージドサービスとして GKE や EKS などで出揃った感はあるけど、マネージドサービスでは k8s クラスタの全ての機能を使うことはできないという認識です。特にネットワークなどインフラよりな低レイヤーな部分はマネージドサービス側でいい感じに隠蔽して、利用者は意識する機会は少ないです。最近は仕事でも k8s など docker コンテナ基盤を扱う機会が増えてきていますが、インフラ屋さんとしてはこのような低レイヤーな部分が気になることがあるので、k8s クラスタを手軽に作れる環境が欲しくなりました。

というわけで、Vagrant を使って手元の仮想環境の管理をしつつ、ansible で k8s クラスタの構築する環境を作りました。ただし、ansible で k8s クラスタを構築する、といっても ansible で完結しておらず、一手間が必要です。というわけで、以下のレポジトリ でどのように k8s クラスタを作っているかを解説してみます。

構築する k8s クラスタ環境

レポジトリの README.md にありますが、構築する環境は以下のようなネットワークになっています。

             client (172.17.1.0/24 / ASN 64512)
-------+--------------+------------
       |              |
   eth1|.1      enp0s8|.10
  +----+----+   +-----+-----+
  |  rt-01  |   | client-01 |
  +----+----+   +-----------+
   eth2|.1
       |                                          k8s-cluster (172.17.0.0/24 / ASN 64522)
-------+-----+------------------+-----------------+-----------------+--------
             |                  |                 |                 |
       enp0s8|.10         enp0s8|.21        enp0s8|.22        enp0s8|.23
     +-------+-------+   +------+------+   +------+------+   +------+------+
     | k8s-master-01 |   | k8s-node-01 |   | k8s-node-02 |   | k8s-node-03 |
     +---------------+   +-------------+   +-------------+   +-------------+

レポジトリ名から予想がつきますが、k8s の LoadBalancer として metallb を使うため、BGP ルーター(rt-01) も構築しています。また、metallb で使用する AS 番号として 64522 を定義しています。また、k8s の CNI プラグインとして flannel を採用しています。各ネットワークのアドレスブロックは以下のようにしています。

  • docker0 : 172.17.255.0/24
  • k8s
    • Flannel Pod Network CIDR : 10.244.0.0/16
    • Service CIDR : 10.244.0.0/16
    • BGP network : 172.17.254.0/24
  • ASNs
    • client 64512
    • k8s-cluster 64522

また、k8s クラスタの管理には kubeadm を全面的に採用しています。

k8s クラスタの構築

k8s 環境の構築

https://github.com/nabeo/vagrant-k8s-metallbgit clone してきたディレクトリで make up を実行します。内部的には各 VM 定義に対して vagrant up が実行され、Vagrantansible_local によるプロビジョニングが実施されます。ansible_local のプロビジョニングでは以下を実施していないため、後の手順で手動で実施する必要があります。

  • k8s-node の k8s クラスタへの参加と worker ノードとしての登録
  • metallb の構築

k8s-node の k8s クラスタへの参加と worker ノードとしての登録

まず、make k8s-master-01-sshk8s-master-01 ノードに ssh ログインします。

k8s-master-01kubeadm token create --print-join-command を実行して、worker ノードが k8s クラスタに参加するためのトークン発行と k8s クラスタに参加する worker ノードで実行するべき kubeadm join コマンドを表示させます。

次に、各 worker ノードで k8s-master-01 ノードで取得した kubeadm join コマンドを実行して、k8s クラスタに参加させます。

この時点では worker ノードは k8s クラスタに参加していますが、worker ノードとしては認識されていないので、k8s-master-01 で以下を実行して worker ノードとして登録します。

kubectl label nodes <hostname> node-role.kubernetes.io/node=
kubectl label nodes <hostname> type=worker

全ての worker ノードの準備が整ったら、 kubectl get nodes では以下のように表示されていると思います。

NAME            STATUS   ROLES    AGE     VERSION
k8s-master-01   Ready    master   42d     v1.15.1
k8s-node-01     Ready    node     42d     v1.15.1
k8s-node-02     Ready    node     5d18h   v1.15.1
k8s-node-03     Ready    node     5d18h   v1.15.1

metallb の構築

Vagrantfile では vm との synced_folder として ansible プレイブックを配置している ansible ディレクトリの他に雑多なファイルを格納するための shared ディレクトリを登録しています。k8s クラスタで使用するマニフェストファイルも shared ディレクトリに配置しています。

ということで k8s-master-01shared/k8s-configs にある以下のファイルを kubectl apply で読み込ませます。

  • metallb.yaml
  • metallb-bgp.yaml

metallb.yaml は metallb の v0.7.3 をベースにして、Vagrant 環境で使えるように調整しています。metallb-bgp.yaml は metallb を BGP モードで使用し、rt-01 に BGP ピアを貼るようにしています。

metallb は k8s クラスタmetallb-system という名前空間を使用しています。1つの controller pod と worker ノード数分の speaker pod が立ち上がっているはずです。

k8s クラスタで遊ぶ

試しに nginx をデプロイしてみます。以下のマニフェストkubectl apply で読み込ませます

---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 6
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-container
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer

ここでは nginx サービスの typeLoadBalancer とすることで metallb を使うようにしています。kubectl apply によって環境がデプロイされると、rt-01 では以下のように nginx サービスの EXTERNAL-IP である 172.17.254.1 の next hop が worker ノードに向いているような経路が BGP で広報されたことがわかります。

vagrant@rt-01:~$ gobgp monitor adj-in
2019-07-27T07:32:17Z [ROUTE] 172.17.254.1/32 via 172.17.0.23 aspath [64522] attrs [{Origin: ?}]
2019-07-27T07:32:17Z [ROUTE] 172.17.254.1/32 via 172.17.0.21 aspath [64522] attrs [{Origin: ?}]
2019-07-27T07:32:17Z [ROUTE] 172.17.254.1/32 via 172.17.0.22 aspath [64522] attrs [{Origin: ?}]

また、rt-01 では gobgpd で受け取った経路を quaggazebraカーネル経路に落とし込んでいるので以下のように ip route でも確認できます。

172.17.254.1 proto zebra metric 20
        nexthop via 172.17.0.22 dev enp0s8 weight 1
        nexthop via 172.17.0.21 dev enp0s8 weight 1
        nexthop via 172.17.0.23 dev enp0s8 weight 1

gobgpdquagga を使った BGP ルータの構築も https://github.com/nabeo/vagrant-k8s-metallb で構築していますが、ここでは詳しくは触れません。

k8s クラスタを kubeadm でアップグレードしたときのメモ

最近は手元で k8s クラスタを作って遊んでいます。いつの間にか k8s の 1.15 系が使えるようになっていたので、kubeadm を使ってクラスタのアップグレードをしてみました。

手順は以下の kubeadm を使った 1.14 から 1.15 へのアップグレード手順をなぞっただけです。

実際に実施した時の手順のメモは以下。

特に複雑なことはしていないクラスタだったので、すんなりアップグレードできてしまった。

ただ、アップグレードが終わった後に kubectl get all とかしていると特定の worker node に割り当たっている coredns の Pod が起動失敗している気配があったので、kubeadm を使って該当 worker node をクラスタから離脱させて再参加させるようなことをしていました。

最近は Vagrant では ansible_local でプロビジョニングしている

vagrant で手元の VirtualBox に検証環境を作る場合は Ansible Local Provisioner を使っています。

昔は Ansible Provisioner を使っていたけど、手元環境を汚さずに仮想ホスト上で ansible を直接実行できることにメリットを感じています。

Vagrantfile はこんな感じで準備しておきます

Vagrant.configure(2) do |config|
  config.vm.synced_folder './ansible', '/home/vagrant/ansible',
                          create: true, owner: 'vagrant', group: 'vagrant'

  config.vm.define 'vm01' do |node|
    node.vm.provider 'virtualbox' do |vb|
      vb.cpus = 1
      vb.memory = 512
      vb.gui = false
    end
    node.vm.hostname = 'vm01'
    node.vm.box = 'ubuntu/cosmic64'
    node.vm.provision :ansible_local do |ansible|
      ansible.compatibility_mode = '2.0'
      ansible.playbook = '/home/vagrant/ansible/all.yml'
      ansible.inventory_path = '/home/vagrant/ansible/inventories/hosts'
      ansible.limit = 'clients'
    end
  end

Vagrantfile があるディクトリに ansible ディレクトリを作って、その下に ansible playbook を配置しています。で、asible ディレクトリは config.vm.synced_folder './ansible', '/home/vagrant/ansible'VM 上の /home/vagrant/ansible として配置しています。

Ansible Local Provisioner を使うときの注意点としては ansible は vm 上で動くため、inventory file は自分自身をプロビジョニング対象にする必要があります。vagrant-hosts プラグインなどを使って hosts ファイルを管理してもいいのですが、僕は inventory file を ansible の role ごとに分けて管理しています。したがって、 ansible ディレクトリの中身はこんな感じになっています

ansible
├── all.yml <--- ansible.playbook で指定している
├── clients.yml
|
├── inventories
│   └── clients <--- ansible.inventory_path で指定している
|
└── roles
    ├── clients
    └── role_template

また、inventory file は ansible をローカル環境を対象に実行する必要があるので、以下のように書いています。

[clients]
127.0.0.1 ansible_connection=local

未来大×企業エンジニア 春の LT 大会で LT してきました #springlt_hakodate

未来大×企業エンジニア 春のLT大会に登壇させてもらえる機会があったので、函館の元気な若者に会いに行ってきました。

お題は「これだけは伝えておきたい技術」ということで、若者に刺さって10分の発表枠に収まりそうな内容ということで、かなり悩みました。そんな悩みを抱えていたある日、社内の若者と雑談していると Docker イメージを小さくするテクニックだと手軽に話せて、かつ、若者に刺さりそう!!ということに気づいたので、こんな資料を作って LT してきました。

大きな講義室にびっしりと聴講者が入ってとても大盛況なかで、「なるほど、最近の学生さんてこういうことに興味あるのか」と発見させられたりととても有意義なイベントでした。また、LT 大会後の懇親会では、自分の学生時代にこんなイベントがあったらもう少し違った学生生活してたかもなーと思いながら話を聞いていました。イベント運営スタッフの皆さん、お疲れ様でした、とても楽しいイベントでした。

また、Tiwtter のタイムラインで指摘されている方もいましたが、DockerCon19 で Dockerfile Best Practices というセッションでイメージサイズの圧縮とは異なる切り口でも触れられているのでより深く知りたい方はオススメです。

あと、スライドの最後にも告知していますが、はてなサマーインターン 2019 の募集が始まっています。興味のある方は応募してください!待ってます!!!

pass で複数のレポジトリを管理する

この記事は仕事用のマシンで pass のレポジトリを統合した時に実施した作業のメモです。

仕事とプライベートの両方でパスワードなど秘密情報の管理に pass を使っています。ただし、仕事の pass は会社のレポジトリ、プライベートの pass はプライベートなレポジトリと管理しているレポジトリが分断していて、仕事で使っているマシンでプライベートなアカウントにログインするときに若干不便を感じていました。しかし、pass は .gpg-id というファイルに複数の GPG 鍵の gpg-id を列挙することで、複数人での秘密情報の共有をサポートしており、レポジトリは git の機能が全て使えます。そこで git の subtree を使って複数のレポジトリを統合して、かつ、仕事用の GPG 鍵と私用の GPG 鍵の両方を使い分けて秘密情報を管理することにしました。

続きを読む

株式会社はてなに入社して1年と1ヶ月が経ちました

早いもので以下のエントリから1年経ちました。

入社した 3/1 に入社して1年経ちましたエントリを書こうと思ったけど、エイプリールフールに入社エントリを書くのは面白かったので、4/1まで待ちました。

ということで、この1年(と1ヶ月)の間、何をしていたかの振り返りです。

続きを読む