はじめに
前回 kubeadm
で Kubernetes のシングルコントロールプレーンのクラスタを構築しました。
今回は kubeadm
と Ansible
を使って HA クラスタを構築しようと思います。
kubeadm
を実行しようにも複数サーバをセットアップには時間がかかるので、Ansible を使って IaC な構築をしようと思います。
がっつりハンズオンな記事なので量がボリューミーなのはご了承ください。
環境情報
OS:Ubuntu 18.04.5 LTS
containerd:1.4.3
kubeadm:v1.20.2
Kubernetes:v1.20.2
kubectl:v1.20.2
Ansible:2.9.17
Role | hostname | CPU | Memory | enp0s3(NAT) | enp0s8(Bridge) |
---|---|---|---|---|---|
ReverseProxy | rp01 | 1 Core | 1 Gi | 10.0.2.15 | 192.168.10.51 |
ControlPlane | cp01 cp02 cp03 |
2 Core | 4 Gi | 10.0.2.15 | 192.168.10.61 192.168.10.62 192.168.10.63 |
Node | nd01 nd02 |
2 Core | 4 Gi | 10.0.2.15 | 192.168.10.71 192.168.10.72 |
あまりに気にしていなかったのですが、Master
⇒ ControlPlane
、Worker
⇒ Node
と呼ばれているんですね。知らなかった・・・
今回も Vagrant/VirtualBox で構築します。
参考までに下記に今回使った Vagrantfile を載せておきます。
※NIC1(enp0s3):NAT、NIC2(enp0s8):ブリッジアダプターで設定しています。
※kubectl exec
で支障がでるため、起動スクリプトでデフォルトゲートウェイをブリッジアダプター側(192.168.10.1)に変更しています。
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.define "rp01" do |server|
server.vm.box = "ubuntu/bionic64"
server.vm.hostname = "rp01"
server.vm.network "public_network", ip: "192.168.10.51"
server.vm.synced_folder ".", "/vagrant", disabled: true
server.vm.provider "virtualbox" do |vb|
vb.customize [
"modifyvm", :id,
"--memory", "1024",
"--cpus", "1"
]
end
server.vm.provision "shell", run: "always", inline: <<-SHELL
sudo ip route del default via 10.0.2.2
sudo ip route add default via 192.168.10.1
SHELL
end
(1..3).each do |i|
config.vm.define "cp0#{i}" do |server|
server.vm.box = "ubuntu/bionic64"
server.vm.hostname = "cp0#{i}"
server.vm.network "public_network", ip: "192.168.10.6#{i}"
server.vm.synced_folder ".", "/vagrant", disabled: true
server.vm.provider "virtualbox" do |vb|
vb.customize [
"modifyvm", :id,
"--memory", "4096",
"--cpus", "2"
]
end
server.vm.provision "shell", run: "always", inline: <<-SHELL
sudo ip route del default via 10.0.2.2
sudo ip route add default via 192.168.10.1
SHELL
end
end
(1..2).each do |i|
config.vm.define "nd0#{i}" do |server|
server.vm.box = "ubuntu/bionic64"
server.vm.hostname = "nd0#{i}"
server.vm.network "public_network", ip: "192.168.10.7#{i}"
server.vm.synced_folder ".", "/vagrant", disabled: true
server.vm.provider "virtualbox" do |vb|
vb.customize [
"modifyvm", :id,
"--memory", "4096",
"--cpus", "2"
]
end
server.vm.provision "shell", run: "always", inline: <<-SHELL
sudo ip route del default via 10.0.2.2
sudo ip route add default via 192.168.10.1
SHELL
end
end
end
Ansible インストール
まずはサーバセットアップ用に Ansible をインストールしていきます。
# Ansible インストールのため python のパッケージマネージャ pip をインストール
$ sudo apt update && sudo apt install python3-pip -y
$ pip3 -V
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)
# Ansible のインストール(今回はバージョンを指定してインストール)
$ sudo pip3 install ansible==2.9.17
$ ansible --version
ansible 2.9.17
・・・
インストールができたので Ansible で各サーバに SSH 接続するための鍵ファイルを作って配布します。
今回は vagrant で実行しているため、vagrant ユーザに公開鍵を追加しています。適宜、作業用のユーザに設定ください。
# Ansible 用の SSH 鍵作成
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/vagrant/.ssh/id_rsa): ★Enter
Enter passphrase (empty for no passphrase): ★Enter
Enter same passphrase again: ★Enter
・・・
# rp01 の vagrant ユーザの公開鍵に鍵を追加
$ cat .ssh/id_rsa.pub >> .ssh/authorized_keys
# 他サーバの vagrant ユーザに公開鍵を追加するため、対象公開鍵を確認
$ cat .ssh/id_rsa.pub
ssh-rsa xxxx root@rp01
# 上記で確認した公開鍵を、各サーバ(cp01~03、nd01~02)にログインし vagrant ユーザの公開鍵に作成した鍵を追記
# vagrant の場合、デフォルトの鍵は消すと SSH ログインできなくなるため、消さずに追記する
$ vi ~/.ssh/authorized_keys
各サーバへの接続準備ができました。Ansible で接続する際の設定ファイルを作成して疎通確認を行っていきます。
# 作業用ディレクトリ作成
$ mkdir -p kubeadm/roles && cd kubeadm
# 以降で以下の構成でファイルを作成する
kubeadm/
├ roles/
├ ansible.cfg :Ansible 設定ファイル
└ inventory :接続先情報ファイル
初回 SSH 接続時の know_hosts
警告文の対応に Ansible の設定ファイルを作成します。
セキュアな接続を行う場合は、一度各サーバへ SSH 接続確認を行うことで以下の設定は不要です。
[defaults]
host_key_checking = False
接続先サーバの情報ファイルを作成します。
各サーバの IP アドレスとグループを分けて登録しました。
[rp]
rp01 ansible_host=192.168.10.51
[cp]
cp01 ansible_host=192.168.10.61
cp02 ansible_host=192.168.10.62
cp03 ansible_host=192.168.10.63
[nd]
nd01 ansible_host=192.168.10.71
nd02 ansible_host=192.168.10.72
準備ができたの Ansible で疎通確認を行います。
# ad-hoc 機能で Ansible のモジュールを直接実行し、接続確認を行う
# -i:接続先情報ファイルを指定
# -m:Ansible モジュール指定。ping モジュールは疎通確認を行う
# all:接続先の引数、inventory ファイルで記載した識別子が指定可能。今回は全てのサーバを指定する all を指定
$ ansible -i inventory -m ping all
cp03 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
・・・
nd02 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
ping - pong で無事に疎通確認が取れました。
共通設定
さて、ここから Ansible の Playbook を作成していきます。
今回は Roles を使って Playbook を取り纏めます。
Roles の簡単な説明は、以下記事を投稿しているのでご参考に。
手始めに共通で利用する Role を作成します。
# 以下の構成でファイルを作成する
kubeadm/
├ ansible.cfg
├ inventory
└ roles/ :各ロール用のディレクトリを配下に配置
└ common/ :共通設定のロール
└ tasks/main.yml :共通の設定タスク
$ pwd
/root/kubeadm
# 共通設定のロールを作成
# 以下コマンドでロールのテンプレート一式が作成される
# --init-path:ロールのテンプレートを指定パス配下に作成する
$ ansible-galaxy role init --init-path roles common
- Role common was created successfully
$ ls roles/
common
最初の Role ができた所で Playbook を作成します。
共通で利用するパッケージのインストールを行うタスクを記述していきます。
Ansible:apt
---
# tasks file for common
- name: Install https repo for apt
apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
update_cache: yes
state: present
実際のロールの指定、実行は以降で合わせて実施します。
ReverseProxy 構築
次に rp01 にリバースプロキシとして nginx
をインストールしていきます。
kubectl
を使ったコントロールプレーンへのリクエストを振り分けます。
# 以下の構成でファイルを作成する
kubeadm/
├ ansible.cfg
├ inventory
├ rp.yml :リバースプロキシ実行用 Playbook
└ roles/
└ reverseproxy/ :リバースプロキシのロール
├ files/nginx.conf :nginx 設定ファイル
├ handlers/main.yml :nginx の設定ファルが書き換わったときの reload Playbook
└ tasks/main.yml :nginx インストール・設定 Playbook
# リバースプロキシのロール作成
$ ansible-galaxy role init --init-path roles reverseproxy
- Role reverseproxy was created successfully
$ ls roles/
common reverseproxy
ロールが作成できたところで、nginx インストールの Playbook を作成していきます。
Playbook のタスク内容は以下の通りです。
- nginx のインストール
- 設定ファイルの配置
- nginx の起動と自動起動の設定
---
# tasks file for reverseproxy
- name: Install nginx
apt:
name: nginx
update_cache: yes
state: present
- name: Copy nginx conf
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
notify: reload_nginx
- name: Start/Enabled nginx
systemd:
name: nginx
enabled: yes
state: started
nginx.conf
が変更された際にも自動で reload
されるように handlers
に処理を記載します。
---
# handlers file for reverseproxy
- name: reload_nginx
systemd:
name: nginx
state: reloaded
task.yaml
で指定した notify: reload_nginx
はファイルの再配置をトリガーに handlers
に通知し、 reload_nginx
を実行する仕組みとなっています。
次に Playbook で配置する nginx の設定ファイルを作成します。今回は最低限の設定のみ記述しています。
※ k8s api リクエストを各コントロールプレーンにリバースプロキシします。
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
}
stream {
upstream kubernetes {
server 192.168.10.61:6443 max_fails=2 fail_timeout=30s;
server 192.168.10.62:6443 max_fails=2 fail_timeout=30s;
server 192.168.10.63:6443 max_fails=2 fail_timeout=30s;
}
server {
listen 6443;
proxy_pass kubernetes;
}
}
最後に作成したロールを実行するための Playbook を作成します。rp グループに所属するサーバに対し、reverseproxy
ロールと先ほど作成した common
ロールの Playbook を実行するように作成します。
- hosts:実行対象
- gather_facts:対象サーバのメタ情報取得要否。OS の種別によって Playbook を変更する場合などの条件分岐させる際に便利。
- become:指定されたユーザでの実行要否。
yes
を指定すると、デフォルトはroot
ユーザになって実行する。 - tags:Playbook 実行時に指定すると実行対象を絞り込む事ができる
---
# file: rp.yml
- hosts: rp
gather_facts: no
become: yes
roles:
- role: common
tags: cmn
- role: reverseproxy
tags: rp
準備が整ったので実行していきます。
1度目の実行で設定を適用し、2度目の実行で設定がちゃんと反映されているか確認します。
※ -C
オプションで dry-run、--diff
オプションで変更前後の diff を出力することもできます。
※ 対象ユーザにパスワードなしの sudo
の許可設定がされていない場合はエラーが出ます。vagrant の場合は /etc/sudoers.d/vagrant
に vagrant ALL=(ALL) NOPASSWD:ALL
が設定されています。必要に応じて設定をお願いします。
$ ansible-playbook -i inventory rp.yml
PLAY [rp] ***************************************************************************************
・・・
TASK [reverseproxy : Install nginx] *************************************************************
changed: [rp01]
・・・
PLAY RECAP **************************************************************************************
rp01 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ ansible-playbook -i inventory rp.yml
・・・
PLAY RECAP **************************************************************************************
rp01 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
全て ok になり、無事に nginx のインストール、設定ファイルの配置が完了しました。
プロキシ先が無いため、とりあえずポートの疎通確認だけ確認します。
$ nc 192.168.10.51 -z 6443 -v
Connection to 192.168.10.51 6443 port [tcp/*] succeeded!
Ansible で Kubernetes セットアップ
最初の Playbook
が実行できたので今度は Kubernetes サーバに適用する Playbook を作成していきます。
まずは全てのロールを作成します。
# ロールのディレクトリ構成
kubeadm/
└ roles/
├ cri/ :CRI(containerd)のロール
├ k8s-server/ :Kubernetes サーバ(kubelet / kubeadm )のロール
└ k8s-client/ :Kubernetes クライアント(kubectl)のロール
# 各ロールの作成
$ ansible-galaxy role init --init-path roles cri
- Role cri was created successfully
$ ansible-galaxy role init --init-path roles k8s-server
- Role k8s-server was created successfully
$ ansible-galaxy role init --init-path roles k8s-client
- Role k8s-client was created successfully
# ls roles/
common cri k8s-client k8s-server reverseproxy
cri
まずはコンテナ実行環境(CRI)として containerd
をインストールします。
# cri ロールのディレクトリ構成
kubeadm/
├ cp.yml :コントロールプレーン実行用 Playbook
├ nd.yml :ノード実行用 Playbook
└ roles/
└ cri/ :CRI(containerd)のロール
├ files/containerd.conf :カーネルモジュール永続化用ファイル
└ tasks/main.yml :Playbook
前述より長めの Playbook ですが、やっていることは以下のとおりです。
- カーネルモジュールのロード
- カーネルモジュール設定の永続化用にファイル配置
- カーネルパラメータの設定
- リポジトリの登録
-
containerd
のインストール
Ansible:modeprobe、copy、sysctl、apt_key、apt_repository、apt、systemd
---
# tasks file for cri
- name: Load kernel module
modprobe:
name: "{{ item }}"
state: present
with_items:
- br_netfilter
- overlay
- name: Copy kernel module load list for boot
copy:
src: containerd.conf
dest: /etc/modules-load.d/containerd.conf
owner: root
group: root
mode: '0644'
- name: Add sysctl conf
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
sysctl_file: /etc/sysctl.d/99-kubernetes-cri.conf
state: present
with_items:
- name: net.ipv4.ip_forward
value: "1"
- name: net.bridge.bridge-nf-call-iptables
value: "1"
- name: net.bridge.bridge-nf-call-ip6tables
value: "1"
- name: Add apt-key for docker
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add apt repository for docker
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable
state: present
- name: Install containerd
apt:
name: containerd.io
update_cache: yes
state: present
- name: Start/Enabled containerd
systemd:
name: containerd
enabled: yes
state: started
カーネルモジュールの設定の永続化は設定ファイルが必要なため、以下ファイルを作成して配置します。
overlay
br_netfilter
CRI インストールの Playbook ができたので、コントロールプレーン、ノードの実行用 Playbook を作成します。
---
# file: cp.yml
- hosts: cp
gather_facts: no
become: yes
roles:
- role: common
tags: cmn
- role: cri
tags: cri
---
# file: nd.yml
- hosts: nd
gather_facts: no
become: yes
roles:
- role: common
tags: cmn
- role: cri
tags: cri
実行用 Playbook ができたのでいざ実行です。
$ ansible-playbook -i inventory cp.yml
PLAY [cp] ***************************************************************************************
・・・
PLAY RECAP **************************************************************************************
cp01 : ok=8 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cp02 : ok=8 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cp03 : ok=8 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ ansible-playbook -i inventory nd.yml
PLAY [nd] ***************************************************************************************
・・・
PLAY RECAP **************************************************************************************
nd01 : ok=8 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
nd02 : ok=8 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
CRI の containerd
がインストールできました。
k8s-server
CRI がインストールできたので、今度はサーバ側で必要な Kubernetes のパッケージをインストールしていきます。
Kubernetes コンポーネントである kubelet
と、インストールツールである kubeadm
をインストールする Playbook を作成していきます。
_/_/_/ k8s-server ロールのディレクトリ構成 _/_/_/
kubeadm/
└ roles/
└ k8s-server/ :Kubernetes サーバ(kubelet / kubeadm )のロール
└ tasks/main.yml :Playbook
インストールの流れは今までと同じような以下の流れです。
- Kubernetes レポジトリ登録
-
kubelet
、kubeadm
のインストール
---
# tasks file for k8s-server
- name: Add apt-key for kubernetes
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: Add apt repository for kubernetes
apt_repository:
repo: deb https://apt.kubernetes.io/ kubernetes-xenial main
state: present
- name: Install kubeadm, kubelet
apt:
pkg:
- kubelet
- kubeadm
update_cache: yes
state: present
先程作成した、cp.yml
と nd.yml
にロールを追加して実行します。
---
# file: cp.yml
- hosts: cp
gather_facts: no
become: yes
roles:
- role: common
tags: cmn
- role: cri
tags: cri
- role: k8s-server
tags: k8ss
---
# file: nd.yml
- hosts: nd
gather_facts: no
become: yes
roles:
- role: common
tags: cmn
- role: cri
tags: cri
- role: k8s-server
tags: k8ss
Playbook にタグを付与したので、タグを指定して追加した Playbook のみ実行します。
$ ansible-playbook -i inventory -t k8ss cp.yml
PLAY [cp] ***************************************************************************************
・・・
PLAY RECAP **************************************************************************************
cp01 : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cp02 : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cp03 : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ ansible-playbook -i inventory -t k8ss nd.yml
PLAY [nd] ***************************************************************************************
・・・
PLAY RECAP **************************************************************************************
nd01 : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
nd02 : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
kubeadm
の実行前の準備が整いました。
k8s-client
kubeadm
を実行する前に もう一つ Kubenetes を操作するクライアントツール(kubectl
)を rp01
にインストールしておきます。
_/_/_/ k8s-client ロールのディレクトリ構成 _/_/_/
kubeadm/
└ roles/
└ k8s-client/ :Kubernetes クライアント(kubectl)のロール
└ tasks/main.yml :Playbook
Playbook では kubectl
のインストールと合わせて、エイリアス(kc
)と補完用の設定を追記します。
※blockinfile
モジュールの中で .bashrc
に設定を追記しています。適宜 path
は変更ください。
Ansible:blockinfile
---
# tasks file for k8s-client
- name: Add apt-key for kubernetes
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: Add apt repository for kubernetes
apt_repository:
repo: deb https://apt.kubernetes.io/ kubernetes-xenial main
state: present
- name: Install kubectl
apt:
pkg:
- kubectl
update_cache: yes
state: present
- name: Add kubectl alias(kc) and register completion
blockinfile:
path: /home/vagrant/.bashrc
block: |
source <(kubectl completion bash)
alias kc=kubectl
complete -F __start_kubectl kc
insertafter: EOF
rp.yml
に追加した Role を追記して実行します。
---
# file: rp.yml
- hosts: rp
gather_facts: no
become: yes
roles:
- role: common
tags: cmn
- role: reverseproxy
tags: rp
- role: k8s-client
tags: k8sc
タグを指定して実行します。
$ ansible-playbook -i inventory -t k8sc rp.yml
PLAY [rp] ***************************************************************************************
・・・
PLAY RECAP **************************************************************************************
rp01 : ok=4 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbooks
今まで作成した資材を以下のとおりです。
kubeadm/
├ ansible.cfg :Ansible 設定ファイル
├ inventory :接続先情報ファイル
├ rp.yml :リバースプロキシ実行用 Playbook
├ cp.yml :コントロールプレーン実行用 Playbook
├ nd.yml :ノード実行用 Playbook
└ roles/
├ common/ :共通設定のロール
│ └ tasks/main.yml
├ reverseproxy/ :リバースプロキシのロール
│ ├ files/nginx.conf
│ ├ handlers/main.yml
│ └ tasks/main.yml
├ cri/ :CRI(containerd)のロール
│ ├ files/containerd.conf
│ └ tasks/main.yml
├ k8s-server/ :Kubernetes サーバ(kubelet / kubeadm )のロール
│ └ tasks/main.yml
└ k8s-client/ :Kubernetes クライアント(kubectl)のロール
└ tasks/main.yml
kubeadm でクラスタ構築
kubeadm
の実行準備ができたのでコントロールプレーンから構築していきます。
先んじてエラー対応のために、containerd
の初期設定ファイルの削除とデーモンの再起動を行います。
# file モジュールを使って設定ファイル削除
$ ansible -i inventory cp,nd -m file -a "path=/etc/containerd/config.toml state=absent" --become
nd02 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"path": "/etc/containerd/config.toml",
"state": "absent"
}
・・・
# systemd モジュールを使ってデーモン再起動
$ ansible -i inventory cp,nd -m systemd -a "name=containerd state=restarted" --become
cp03 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"name": "containerd",
"state": "started",
"status": {
・・・
最初の一台目のコントロールプレーンを構築します。
cp01
にログインし、kubeadm
を実行します。
_/_/_/ 一台目のコントロールプレーンを構築 _/_/_/
# --control-plane-endpoint:コントロールプレーンのエンドポイント
# ⇒ 今回はリバースプロキシのサーバを経由してコントロールプレーンへのリクエストを受けるため指定
# --pod-network-cidr:Pod に割り振られる IP アドレスレンジ
# ⇒ デフォルトだと LAN と被ったので指定
# --apiserver-advertise-address:API サーバーが待ち受けする IP アドレス
# ⇒ Vagrant デフォルトだと NAT の NIC で動作不良起こしそうだったので、ブリッジの NIC を指定
# --upload-certs:コントロールプレーンノードで共有する必要がある証明書をクラスタにアップロード(Secret)
# ⇒ 複数コントロールプレーンノードを作成する場合は指定(手動で証明書配布する場合は不要)
# ⇒ インストール出力を見るに有効期限は2時間?
# 参考:https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/high-availability/#manual-certs
$ sudo kubeadm init \
--control-plane-endpoint "192.168.10.51:6443" \
--pod-network-cidr 172.16.0.0/16 \
--apiserver-advertise-address 192.168.10.61 \
--upload-certs
[init] Using Kubernetes version: v1.20.2
・・・
Your Kubernetes control-plane has initialized successfully!
・・・
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join 192.168.10.51:6443 --token xxxx \
--discovery-token-ca-cert-hash sha256:xxxx \
--control-plane --certificate-key xxxx
・・・
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.10.51:6443 --token xxxx \
--discovery-token-ca-cert-hash sha256:xxxx
1~3分ほどで無事にインストールができると思います。
出力内容のトークンなどはこの後利用するので、結果は保存しておきましょう。
続いてネットワークプラグイン(Project Calico)をインストールします。
インストールには kubectl
を使うため、接続用の設定ファイルを cp01 から取得し rp01 に配置します。
# Kubernetes に接続する際の設定ファイルを取得
$ mkdir ~/.kube
$ ssh 192.168.10.61 "sudo cat /etc/kubernetes/admin.conf" > ~/.kube/config
$ kubectl get node
NAME STATUS ROLES AGE VERSION
cp01 NotReady control-plane,master 30m v1.20.2
# ネットワークプラグインのデプロイ
$ kubectl apply -f https://docs.projectcalico.org/v3.17/manifests/calico.yaml
・・・
daemonset.apps/calico-node created
・・・
$ kubectl get node
NAME STATUS ROLES AGE VERSION
cp01 Ready control-plane,master 32m v1.20.2
1台目のコントロールプレーンが無事に起動できたところで、2台目 / 3台目を追加します。
実行用のコマンドは1台目をインストールした際に出力されています。今回はそちらに --apiserver-advertise-address
オプションで IP アドレスを指定しています(以下コマンドは改行をいれて整形しています)。
cp02
、cp03
にログインし実行していきます。
# cp02
sudo kubeadm join 192.168.10.51:6443 \
--token xxxx \
--discovery-token-ca-cert-hash sha256:xxxx \
--certificate-key xxxx \
--control-plane \
--apiserver-advertise-address 192.168.10.62
# cp03
sudo kubeadm join 192.168.10.51:6443 \
--token xxxx \
--discovery-token-ca-cert-hash sha256:xxxx \
--certificate-key xxxx \
--control-plane \
--apiserver-advertise-address 192.168.10.63
コントロールプレーンが HA 構成の3台で稼働できたことを確認します。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
cp01 Ready control-plane,master 41m v1.20.2
cp02 Ready control-plane,master 2m49s v1.20.2
cp03 Ready control-plane,master 77s v1.20.2
次にノードを追加します。こちらもアドレスを指定して実行します。実行コマンドはコントロールプレーンの1台目をインストールした時に出力されています。コントロールプレーンの2台目、3台目をインストールした時と同様に IP アドレスを指定して実行します。
# nd01
$ sudo kubeadm join 192.168.10.51:6443 \
--token xxxx \
--discovery-token-ca-cert-hash sha256:xxxx \
--apiserver-advertise-address 192.168.10.71
# nd02
$ sudo kubeadm join 192.168.10.51:6443 \
--token xxxx \
--discovery-token-ca-cert-hash sha256:xxxx \
--apiserver-advertise-address 192.168.10.72
ノードが2台構成で稼働していることを確認します。
$ kc get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
cp01 Ready control-plane,master 9m30s v1.20.2 192.168.10.61 <none> Ubuntu 18.04.5 LTS 4.15.0-124-generic containerd://1.4.3
cp02 Ready control-plane,master 5m3s v1.20.2 192.168.10.62 <none> Ubuntu 18.04.5 LTS 4.15.0-124-generic containerd://1.4.3
cp03 Ready control-plane,master 3m51s v1.20.2 192.168.10.63 <none> Ubuntu 18.04.5 LTS 4.15.0-124-generic containerd://1.4.3
nd01 Ready <none> 2m45s v1.20.2 192.168.10.71 <none> Ubuntu 18.04.5 LTS 4.15.0-124-generic containerd://1.4.3
nd02 Ready <none> 99s v1.20.2 192.168.10.72 <none> Ubuntu 18.04.5 LTS 4.15.0-124-generic containerd://1.4.3
動作確認
クラスタが構築できたので動作確認をします。
# Pod 作成
$ kubectl run nginx --image=nginx --port=80
pod/nginx created
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 22s 172.16.246.1 nd01 <none> <none>
# Pod 内でバージョン確認
$ kubectl exec nginx -- nginx -v
nginx version: nginx/1.19.6
# Service(NodePort)を公開
$ kubectl expose pod nginx --type=NodePort
service/nginx exposed
# Worker の IP、Service の NodePort を取得して Pod にアクセス
$ IP=`kubectl get node nd01 -o=jsonpath='{.status.addresses[?(@.type == "InternalIP")].address}'`
$ PORT=`kubectl get svc nginx -o yaml -o=jsonpath='{.spec.ports[0].nodePort}'`
$ curl -I http://$IP:$PORT/
HTTP/1.1 200 OK
Server: nginx/1.19.6
Date: Fri, 12 Feb 2021 17:18:00 GMT
Content-Type: text/html
・・・
まとめ
長いハンズオンお疲れさまでした。Ansible でコード化することで、複数サーバで実行しなければならないコマンドも一発で実行することができたかと思います。また、1度作成したコード群は追加サーバのセットアップなど、その後のクラスタ構築の時間を短縮することができます。ひいてはいつでも壊せるクラスタを構築することができるのではと思います。
今回はコントロールプレーンやノードに特別な設定を加えていませんが、OS の設定(ユーザ追加やディスク管理)や個々のサーバへの設定を追加していくこともできるので応用の幅は広いかと思います。
kubeadm
って本当に便利ですね、開発者に感謝です。
参考