Ansibleを使ってさくらのVPSにk8sクラスタを構築した
CyberAgentグループでサーバサイドエンジニアをしている yamaguchi naoto です。
CyberAgentメディア管轄の広告プロダクト横断組織(PTA)によるアドベントカレンダー2020最終日の投稿になります。
CyberAgent PTA Advent Calendar
前日は同僚の古川による「YAML+Mustache+go-generate で go の メタプログラミング をする」でした。
今回はAnsibleを使ってさくらのVPSにk8sクラスタを構築したことについて書きたいと思います。
はじめに
今年参加している新規プロジェクトでk8sが採用されました。自分はまだ触れたことがなかったので理解を深めるためにVPSに構築してみることにしました。
kubesplay や さくらのスタートアップスクリプト などありますが、せっかくなのでそれらで使用されている kubeadm を使ってAnsibleのPlaybookを組むことにしました。
この記事では下記のPlaybookでやっていることをざっくり紹介していきます。
Playbook
まだ荒削りですが下記に公開しています。
https://github.com/naoto0822/k8s-sakuravps-playbook
環境
1GプランでマスターノードはメモリもCPUも余裕がなくsshもままならなかったので、マスターノードのみ2Gプランとしました。https://vps.sakura.ad.jp/specification/
- CentOS 7
- k8s v1.19.4
- kubeadm v1.19.4
- Ansible 2.10.3
- さくらのVPS 2Gプラン (マスターノード)
- さくらのVPS 1Gプラン * 2 (ワーカーノード)
構成図
- マスターノード1台、ワーカーノード2台
- 自分のPCからインターネット経由で `kubectl` コマンド使える
- さくらのローカルスイッチを使ってクラスタ間の通信はプライベートネットワークでおこなっている
さくらVPSの設定
sshの設定含めてplaybookのroleはcommonになります。
1. ローカルスイッチ
クラスタ間の通信はプライベートネットワークでおこないたいための設定になります。全台ローカルスイッチを設定します。
またプライベートIPを割り当てたネットワークインターフェースを追加して networkを再起動してください。
$ cat ifcfg-eth1NAME="eth1"
DEVICE="eth1"
IPADDR="{{ node_ip }}"
NETMASK="255.255.255.0"
ONBOOT="yes"
TYPE="Ethernet"
IPV6INIT="no"
IPV6_ROUTER="no"
ZONE="internal"
2. パケットフィルタの設定をオフ
Playbook上はパケットフィルタの設定がオフであることを前提としています。
k8sのインストール
playbookのroleはk8sとなります
主にkubelet, kubeadm, kubectlをインストールして構築していきます。違いについては 公式ドキュメント に説明が載っています。
基本的には「kubeadmのインストール」に載っている公式ドキュメントに従って準備していきます。
1.下準備
Node共通して下記を実施しています。
- swap off
- iptablesの設定
- port開放 (MasterとWorkerで必須ポートが違う模様。公式ドキュメント)
2. Docker Install
次にDockerのInstallして起動してください
- name: Add Docker repo
get_url:
url: https://download.docker.com/linux/centos/docker-ce.repo
dest: /etc/yum.repos.d/docker-ce.repo
become: yes
tags: k8s- name: Install docker
yum:
name: docker-ce
state: present
tags: k8s- name: Start service docker, and enable service docker
systemd:
name: docker.service
state: started
daemon-reload: yes
enabled: yes
tags: k8s
3. kubelet, kubeadm Install
k8sを構成するものをInstallします。
- name: Add kubernetes repo
yum_repository:
name: kubernetes
description: kubernetes repo
baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
gpgcheck: no
enabled: yes
tags: k8s- name: Install kubelet kubeadm
yum:
name: "{{ packages }}"
vars:
packages:
- kubelet
- kubeadm
state: present
tags: k8s
またkubeletがPrivateIPをbindするように`/etc/sysconfig/kubelet`に下記のファイルを置いてください。その後kubeletを起動してください。
KUBELET_EXTRA_ARGS=--node-ip={{ node_ip }}
Master Nodeの構築
playbookのroleはk8s-masterとなります
1. kubeadmの起動
下記コマンドでkubeadmを起動します。
$ kubeadm init --pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address={{ node_ip }} \
--apiserver-cert-extra-sans={{ node_ip }},{{ global_ip }}
- pod-network-cidrは後述のネットワークアドオンであるFlannelの指定引数となります
- apiserver-advertise-addressはapiserverが待ち受けを行うIPを指定できます。今回はPrivate IPを指定しています。
- インターネット越しにkubectlコマンドが叩けるように証明書のSANsにglobal_ipを追加します
2. join command発行
Worker Nodeがクラスターに参加するために実行するコマンドを発行します。コマンドにはExpireがあってデフォルトで24hです。
$ kubeadm token create --print-join-command
3. Podネットワークアドオンのインストール
今回はFlannelを採用しました。アドオンごとの設定はkubeadmのドキュメントにそれぞれ詳細が記載されています。
manifestsを落として修正します。
$ wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
何も指定しないとFlannelはデフォルトのネットワーク・インターフェースを指定するようなので、Private IPのネットワーク・インターフェースを指定するようにManifestsを修正します。( Flannel公式ドキュメント )
修正後applyします。またUDPポート8285と8472を開けてください。
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.13.1-rc1
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
+ - --iface=eth1 # 追加
Worker Nodeの構築
playbookのroleはk8s-workerとなりますが、join commandの連携が自動化されていません。
Master Nodeで吐き出したjoin commandをWorker Nodeで実行することで、クラスターに追加されます。
$ kubeadm join 10.1.0.10:6443 --token aaaaaa.hogehoge \
--discovery-token-ca-cert-hash sha256:hogehogehogehoge
最後にMaster Nodeにsshしてkubectlで確認します。これで完了です。
[k8s@tk2-foo-hoge ~]$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
tk2-foo-hoge.vs.sakura.ne.jp Ready <none> 20d v1.19.4
tk2-foo-hoge.vs.sakura.ne.jp Ready <none> 20d v1.19.4
tk2-foo-hoge.vs.sakura.ne.jp Ready master 20d v1.19.4
インターネットからkubectlする
公式ドキュメントにある通りMaster Nodeで生成されたadmin.confを渡すことで他のマシーンからもkubectlを実行できるようになります。ただ今回はPrivate IPで設定してきたのでadmin.confのserver指定もPrivate IPになっています。
scpでMaster Nodeからadmin.confを落としたらserverのディレクティブをGlobal IPに変えます。kubeadm init時に — apiserver-cert-extra-sansにIPを追記していることで可能になるようです。
# L5ぐらいの下記箇所をGlobal IPに書き換える
server: https://${ip_address}:6443
その後環境変数を読み込んで実行します。
> export KUBECONFIG=~/.kube/config:~/Documents/workspace/src/github.com/naoto0822/k8s-sakuravps-playbook/.admin.conf> kubectl get nodes
NAME STATUS ROLES AGE VERSION
tk2-foo-hoge.vs.sakura.ne.jp Ready <none> 20d v1.19.4
tk2-foo-hoge.vs.sakura.ne.jp Ready <none> 20d v1.19.4
tk2-foo-hoge.vs.sakura.ne.jp Ready master 20d v1.19.4
これでlocalで開発したManifestsを自由にapplyできるようになりました。
まとめ
ansibleを使ってさくらVPSにk8sクラスタを構築してみました。ハマった箇所はいくつかありますがkubeadmを使えば割とカジュアルに構築できることがわかりました。年末年始はこれをつかって遊ぼうとおもいます。
最後に
以上PTAのアドベントカレンダーでした!!!
メリー・クリスマス!!!