Help us understand the problem. What is going on with this article?

[outdated] rak8sを利用してRaspberry PiにKubernetes環境を構築する

この記事で利用しているrak8sは更新されていませんので、Raspberry Pi上にKubernetes環境を構築する場合には、k3s を利用してください。

はじめに

Raspberry Piを利用してKubernetesクラスターを構築してみようと調べたところ、rak8s.ioに行きあたったので試してみました。

結果としては、Kubernetesのバージョンが古かったり、微妙な不具合があったので、ansible taskを少し修正するなどしています。

環境

このセクションの作業は、ノートPCなどのコンピュータ側で行ないます。

ansible実行環境

  • Ubuntu 18.04.2 LTS (amd64版) on VMware Workstation 15
  • PPA - Ansible
/etc/apt/sources.list.d/ansible-ubuntu-ansible-bionic.list
deb http://ppa.launchpad.net/ansible/ansible/ubuntu bionic main
deb-src http://ppa.launchpad.net/ansible/ansible/ubuntu bionic main

Kubernetes用

  • Raspberry Pi 3 and 3+ (IPv4 address: 192.168.1.77/24, 192.168.1.78/24)
  • Raspbian Lite (2018-11-13版)

rak8s.ioのgithubリポジトリをforkしたリポジトリ(https://github.com/YasuhiroABE/rak8s)を公開しています。

次の要領で利用できます。

$ git clone https://github.com/YasuhiroABE/rak8s.git
$ cd rak8s
$ git checkout -b v1.13.5 origin/v1.13.5

ansible-playbookコマンドを実行するための準備

この作業はRaspberry Piの全台で実施してください。

静的IPアドレスの設定

手元の環境はdnsmasqを動かしているので、MACアドレスから固定IPを割り当てるようにしています。

DHCPサーバーに手を入れることができないのであれば、/etc/dhcpcd.confファイルを変更します。

/etc/dhcpcd.confの編集例
# Example static IP configuration:
interface eth0
static ip_address=192.168.0.10/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1

$ ip addrコマンドでIPアドレスが意図したアドレスに変更されていない場合は、確認を兼ねて再起動がお勧めです。

Locale等の変更

配布されているRaspbian Liteのイメージから起動すると、sshサーバーは無効化されています。
そのため、あらかじめsshサーバーを起動しておくか、初回はHDMIケーブルとキーボードを接続し、raspi-configコマンド等からsshを有効化しておきます。

raspi-configの起動
$ sudo raspi-config

起動した後は、5.Interfacing Optionsを選択し、2番目のSSHからYESを選択し、サーバーを起動させます。

image.png

Raspbian Liteのデフォルトロケールはイギリス英語なので、en_US.UTF-8がデフォルトになるように、4. Localisation Optionsを選択します。
遷移した画面で、Localeを変更し、en_GB.UTF-8を外し、en_US.UTF-8がデフォルトになるように変更しています。

image.png

お勧め設定として、GPUメモリをデフォルトの64MBから16MBに変更することが https://rak8s.io/ に記載されています。
この設定をしないとansible-playbookを実行した時にエラーになるので、変更しておきます。
"7. Advanced Options"に進み、"A3. Memory Split"メニューから変更します。

image.png
image.png

Timezoneについては、ansibleがUTCに変更するので、何も設定していません。

authorized_keysファイルの配置

パスワードなしにsshで実行できるように、ansible実行環境のUbuntuにある公開鍵をコピーしています。

今回はed25519形式を利用したかったので、新たに鍵を生成しています。
Raspberry Pi側で何もしていないと~/.ssh/ディレクトリが存在していないので、作成し、パスワードを入力して公開鍵を適切な場所にコピーしています。

$ ssh-keygen -t ed25519
...
$ ssh pi@192.168.1.77 mkdir --mode=700 .ssh
$ scp ~/.ssh/id_ed25519.pub pi@192.168.1.77:.ssh/authorized_keys
$ ssh pi@192.168.1.78 mkdir --mode=700 .ssh
$ scp ~/.ssh/id_ed25519.pub pi@192.168.1.78:.ssh/authorized_keys

kernelのアップデート

デフォルトの4.14.98-v7+から、4.19.30-v7+に変更しています。

$ sudo rpi-update

ansibleによるkubernetes環境の構築

ここからの作業はノートPCなどのコンピュータ側で行ないます。
あらかじめrak8sのディレクトリに移動しておきます。

inventoryファイルの変更

まず、inventoryファイルを変更します。

./inventoryファイル
[prod]
rak8s002    ansible_host=192.168.1.79
rak8s003    ansible_host=192.168.1.80

[master]
rak8s002

group_vars/all.yml ファイルの修正

バージョンの指定を最新のv1.13.4に合わせます。
docker-ceは18.09でも動作確認はしているはずですが、ここでは18.06を指定しています。

all.ymlファイルにはpodnet変数が設定されていますが、途中で変更するとcleanup.ymlを使用しても、正常に変更が反映されずに残るようなので気をつけてください。

group_vars/all.yml
diff --git a/group_vars/all.yml b/group_vars/all.yml
index a4eb864..54053ff 100644
--- a/group_vars/all.yml
+++ b/group_vars/all.yml
@@ -1,7 +1,7 @@
 token: udy29x.ugyyk3tumg27atmr
 podnet: 10.244.0.0/16

-kubernetes_package_version: "1.11.4-00"
+kubernetes_package_version: "1.13.4-00"
 # Available versions:
 # 1.10.3-00
 # 1.10.2-00
@@ -12,7 +12,7 @@ kubernetes_package_version: "1.11.4-00"
 # 1.9.6-00
 # 1.9.5-00

-kubernetes_version: "v1.11.4"
+kubernetes_version: "v1.13.4"
 # Available versions:
 # v1.10.3
 # v1.10.2
@@ -23,7 +23,7 @@ kubernetes_version: "v1.11.4"
 # v1.9.6
 # v1.9.5

-docker_ce_version: "18.04.0~ce~3-0~raspbian"
+docker_ce_version: "18.06.3~ce~3-0~raspbian"
 # Available versions:
 # 18.05.0~ce~3-0~raspbian
 # 18.04.0~ce~3-0~raspbian

roles/master/tasks/main.ymlファイルの修正

v1.13.4を前提にtask/main.ymlファイルを修正しています。

roles/master/tasks/main.yml
diff --git a/roles/master/tasks/main.yml b/roles/master/tasks/main.yml
index 99124bc..e957007 100644
--- a/roles/master/tasks/main.yml
+++ b/roles/master/tasks/main.yml
@@ -5,7 +5,7 @@
   register: kubeadm_reset

 - name: "Initialize Master {{ kubernetes_version }}"
-  shell: kubeadm init --apiserver-advertise-address={{ ansible_default_ipv4.address }} --token={{ token }} --kubernetes-version={{ kubernetes_version }} --pod-network-cidr={{ podnet }}
+  shell: kubeadm init --apiserver-advertise-address={{ ansible_default_ipv4.address }} --token={{ token }} --kubernetes-version={{ kubernetes_version }} --pod-network-cidr={{ podnet }} --ignore-preflight-errors=SystemVerification
   register: kubeadm_init
   when: kubeadm_reset is succeeded

@@ -34,7 +34,7 @@
   register: kubeadm_join

 - name: Install Flannel (Networking)
-  shell: "curl -sSL https://rawgit.com/coreos/flannel/{{ flannel_version }}/Documentation/kube-flannel.yml | sed 's/amd64/arm/g' | kubectl create -f -" 
+  shell: "curl -sSL https://raw.githubusercontent.com/coreos/flannel/{{ flannel_version }}/Documentation/kube-flannel.yml | sed 's/amd64/arm/g' | kubectl create -f -" 

 - name: Poke kubelet
   systemd:

ansible-playbookコマンドの実行の前に

これまで試したところ、直接 ansible-playbook コマンドを実行すると、python-aptのタスクで停止しました。
そのため事前にapt-getコマンドを実行しています。

rak8sディレクトリの中にいる状態(カレントディレクトリにansible.cfgファイルがる状態)で、次のコマンドを実行します。

$ ansible all -m command -b -a "apt-get update"
$ ansible all -m command -b -a "apt-get -y dist-upgrade"

いろいろ変更されていると思うので、ここで再起動しておきます。

$ ansible all -m command -b -a "shutdown -r now"

ansible-playbookコマンドの実行

引き続き、ansible実行側の環境で作業を進めます。

$ ansible-playbook cluster.yml

初回の起動は次のようなメッセージがでて、いくつかTaskが実行されて失敗するので、ノードを再起動してから続けます。

TASK [common : Reboot Message] *******************************************************************************
ok: [rak8s002] => {
    "msg": "A reboot is required but the reboot module is a little wonky. Hopefully someone fixes this soon."
}
...
TASK [kubeadm : Run Docker 18.06.3~ce~3-0~raspbian Install Script] *******************************************
fatal: [rak8s002]: FAILED! => ...
... OR ...
TASK [master : Initialize Master v1.13.5] ********************************************************************
fatal: [rak8s000]: FAILED! => ...

最初のapt dist-upgradeの後で再起動する・しない、といった状況によって停止する場所は違いました。
再起動はansibleコマンドを使っています。

$ ansible all -m command -b -a "shutdown -r now"

しばらく待ってノードの稼動を$ ansible all -m pingなどで確認しつつ、再度ansible-playbookコマンドを実行します。

$ ansible-playbook cluster.yml

確認した環境では、これでエラーなく完了しています。

稼動確認

podはあっても起動しているか、再起動を繰り返していないか、きちんと確認しておく必要があります。
最初にrak8sを利用した時は、いろいろ動かないところがあって苦労しました。

ただ全体が起動するまでに8分前後の時間がかかっています。

作業を簡単にするために、以下のようなaliasを利用しています。

~/k8s.envrc
alias kc="sudo kubectl -n kube-system"
alias kcg="kc get"
alias kcga="kcg all"
alias kcgan="kcga --all-namespaces"
alias kcd="kc describe"

2回目のansible-playbook cluster.ymlが終わった後で、5分程度経過してからkubectlコマンドを実行した結果は次のようになりました。

稼動確認の様子
$ . ~/k8s.envrc
$ kcg pod   ## "sudo kubectl -n kube-system get pod" のエイリアス
NAME                               READY   STATUS    RESTARTS   AGE
coredns-86c58d9df4-7bkfz           1/1     Running   0          3m51s
coredns-86c58d9df4-jzggq           1/1     Running   0          3m51s
etcd-rak8s000                      1/1     Running   0          3m44s
kube-apiserver-rak8s000            1/1     Running   1          4m7s
kube-controller-manager-rak8s000   1/1     Running   0          3m44s
kube-flannel-ds-arm-5hss9          1/1     Running   1          3m15s
kube-flannel-ds-arm-7vxwg          1/1     Running   0          3m40s
kube-proxy-frfhx                   1/1     Running   0          3m51s
kube-proxy-v9fgh                   1/1     Running   0          3m15s
kube-scheduler-rak8s000            1/1     Running   0          3m44s

ここでRESTARTSのカウントが上がり続けないか、2〜3分間隔を開けて確認します。

問題がなければ、coreDNSを中心に、きちんとコンテナが稼動することを確認するために、metallbとnginxをデプロイしてみます。

metaillbのデプロイメント

あらかじめaliasを設定するためのファイルを準備しておきます。

~/k8s.envrc.metallb
test -f ~/k8s.envrc && . ~/k8s.envrc
alias kc="sudo kubectl -n metallb-system"

実際の作業は次のようになっています。

$ . ~/k8s.envrc.metallb
$ kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml
## 適当なエディタで次のような内容のlayer2-config.yamlファイルを作成する
$ cat layer2-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.1.83-192.168.1.84
$ kc apply -f layer2-config.yaml
$ kcga
NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-7cc9c87cfb-wgn82   1/1     Running   0          12m
pod/speaker-5zp6x                 1/1     Running   0          12m

NAME                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/speaker   1         1         1       1            1           <none>          12m

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           12m

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-7cc9c87cfb   1         1         1       12m

nginxによるmetallbの稼動確認

metallbと同様にaliasを設定するためのファイルを準備します。

~/k8s.envrc.nginx
test -f ~/k8s.envrc && . ~/k8s.envrc
alias kc="sudo kubectl -n nginx"

実際の作業は次のようになっています。

$ . ~/k8s.envrc.nginx
$ kc create ns nginx
$ cat deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15
        ports:
        - containerPort: 80
$ kc apply -f deployment.yaml
$ cat service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
$ kc apply -f service.yaml
$ kcga
NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-5fc86c987f-xcl8c   1/1     Running   0          13m

NAME            TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
service/nginx   LoadBalancer   10.105.192.198   192.168.1.83   80:30043/TCP   13m

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   1/1     1            1           13m

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-5fc86c987f   1         1         1       13m

EXTERNAL-IPがきちんとConfigMAPで指定したレンジから割り振られていれば完了です。

この他のTips

rak8sでは毎回$ sudo kubectl ...とsudoで指定していますが、/root/.kube/config には必要なファイルはansibleで配置されています。

piユーザーのままでkubectlをsudoなしに実行したければ、同様にファイルをコピーすれば可能です。

$ mkdir -m 700 ~/.kube/
$ sudo cp /root/.kube/config ~/.kube/config
$ sudo chown -R pi:pi  ~/.kube/.

以上

YasuhiroABE
元エンジニアの大学教員@会津大学。ここに投稿している内容は、個人的な動機・責任で編集しているもので、勤務先・業務とは関係ありません。なお、LGTM(評価)・ストックされた記事は、その都度、可能な範囲で見直すようにしています。
https://www.yadiary.net/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした