とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

自宅にK8sを召喚したい(K8sセットアップ編)

前回からの続き。Proxmoxに作ったk8s1をクローンしてk8s3まで増やします。とりあえずk8s1で必要なソフトウェアのインストールとかセットアップとか済ませてからクローンしましょう。

セットアップ

ひとまずWebコンソールから設定していきます。

1. ホスト名の設定

$ sudo hostnamectl set-hostname k8s1
$ sudo sed "s/ubuntu/k8s1/" -i /etc/hosts

2. timezoneをJSTに

$ sudo timedatectl set-timezone Asia/Tokyo

3. opensshをインストール(オプショナル)

$ sudo apt install -U -y ssh

4. microk8sのインストール   素のK8sでもいいんですが、今回はmicrok8sにします。楽したい

$ sudo snap install microk8s --classic

インストールが完了したらstatusを確認してみましょう。

$ sudo microk8s status
microk8s is running
high-availability: no
  datastore master nodes: 127.0.0.1:19001
  datastore standby nodes: none
addons:
  enabled:
    dns                  # (core) CoreDNS
    ha-cluster           # (core) Configure high availability on the current node
    helm                 # (core) Helm - the package manager for Kubernetes
    helm3                # (core) Helm 3 - the package manager for Kubernetes
  disabled:
    cert-manager         # (core) Cloud native certificate management
    cis-hardening        # (core) Apply CIS K8s hardening
    community            # (core) The community addons repository
    dashboard            # (core) The Kubernetes dashboard
    gpu                  # (core) Alias to nvidia add-on
    host-access          # (core) Allow Pods connecting to Host services smoothly
    hostpath-storage     # (core) Storage class; allocates storage from host directory
    ingress              # (core) Ingress controller for external access
    kube-ovn             # (core) An advanced network fabric for Kubernetes
    mayastor             # (core) OpenEBS MayaStor
    metallb              # (core) Loadbalancer for your Kubernetes cluster
    metrics-server       # (core) K8s Metrics Server for API access to service metrics
    minio                # (core) MinIO object storage
    nvidia               # (core) NVIDIA hardware (GPU and network) support
    observability        # (core) A lightweight observability stack for logs, traces and metrics
    prometheus           # (core) Prometheus operator for monitoring and logging
    rbac                 # (core) Role-Based Access Control for authorisation
    registry             # (core) Private image registry exposed on localhost:32000
    rook-ceph            # (core) Distributed Ceph storage using Rook
    storage              # (core) Alias to hostpath-storage add-on, deprecated

addonは必要なものを有効化するといいですが、今回はとりあえずhostpath-storageとingressくらい有効化しておきます。使うかはわかりません。

$ sudo microk8s enable hostpath-storage
Infer repository core for addon hostpath-storage
Enabling default storage class.
WARNING: Hostpath storage is not suitable for production environments.
         A hostpath volume can grow beyond the size limit set in the volume claim manifest.

deployment.apps/hostpath-provisioner created
storageclass.storage.k8s.io/microk8s-hostpath created
serviceaccount/microk8s-hostpath created
clusterrole.rbac.authorization.k8s.io/microk8s-hostpath created
clusterrolebinding.rbac.authorization.k8s.io/microk8s-hostpath created
Storage will be available soon.

$ sudo microk8s enable ingress
Infer repository core for addon ingress
Enabling Ingress
ingressclass.networking.k8s.io/public created
ingressclass.networking.k8s.io/nginx created
namespace/ingress created
serviceaccount/nginx-ingress-microk8s-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-microk8s-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-microk8s-role created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-microk8s created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-microk8s created
configmap/nginx-load-balancer-microk8s-conf created
configmap/nginx-ingress-tcp-microk8s-conf created
configmap/nginx-ingress-udp-microk8s-conf created
daemonset.apps/nginx-ingress-microk8s-controller created
Ingress is enabled

実はmicrok8sをインストールした時点でK8sのインストールって終わってしまってるんですよね。K8sにアクセスできるか確認してみます。

$ sudo microk8s.kubectl get nodes
NAME     STATUS   ROLES    AGE     VERSION
ubuntu   Ready    <none>   9m39s   v1.32.9

ノードが見れました。ただちょっとkubectlコマンドが叩きづらいので、先頭のmicrok8s.を省略できるようにしておきましょう。

$ sudo snap alias microk8s.kubectl kubectl

これでkubectlコマンド単体でも実行できるようになりました。

$ kubectl
Insufficient permissions to access MicroK8s.
You can either try again with sudo or add the user ubuntu to the 'microk8s' group:

    sudo usermod -a -G microk8s ubuntu
    sudo chown -R ubuntu ~/.kube

After this, reload the user groups either via a reboot or by running 'newgrp microk8s'.

sudoをつけ忘れて↑のようなエラーが出てしまいました。microk8sグループに所属する必要があるみたいですね。sudoなしで実行したい方は下記

$ sudo usermod -a -G microk8s ubuntu    # `ubuntu`の部分はログイン中のユーザー名に変更

$ sudo chown -R ubuntu ~/.kube

~/.kubeがまだ存在していない環境ではchownはエラーになると思いますが、~/.kubeがないなら問題ないです。

一度ログアウト&ログインして再度確認

$ kubectl get nodes
NAME     STATUS   ROLES    AGE   VERSION
ubuntu   Ready    <none>   15m   v1.32.9

最後にローカルマシンからアクセスできるようにします。

ここまでの設定だけだとk8s1サーバーに乗り込んでK8sを操作することになりますが、それだと何かと不便です。そこでアクセスするための情報を出力してローカルマシンにコピーします。

microk8s config | sed "s/microk8s/$HOSTNAME/; s/admin/$HOSTNAME-admin/" > kubeconfig

ここで生成されたkubeconfigをローカルマシンの~/.kube/configにコピーしてください。すでに~/.kube/configが存在している場合はバックアップをとっておくのがいいでしょう。なお、ローカルマシンにkubectlコマンドが入っていない場合はこちらの手順でインストールしておきましょう。

$ mkdir ~/.kube
$ scp k8s1:kubeconfig ~/.kube/config

ローカル環境からkubectlコマンドが実行できればOKです。

$ kubectl get nodes        
NAME   STATUS   ROLES    AGE   VERSION
ubuntu   Ready    <none>   65m   v1.32.9

初期設定はこの辺で

5. クローン

対象のVMを右クリックするとコンテキストメニューが出てきます。

下から3番目に「Clone」とあるのでこちらをクリック

VM名などの入力を促されるので「k8s2」と入力しましょう。

上記の手順で「k8s3」まで増やしておいてください。

k8s2と3はk8s1のノードとして追加します。

6. クローンしたVMの設定

クローンしたVMを起動してみましょう。

全ての設定が引き継がれているので、当然ですがk8s2のホスト名が「k8s1」になっています。

ホスト名だけならいいですが、IPアドレスを確認してみてください。1と2で同じIPになってると思います。

どちらも「192.168.100.142」になっています。

これはProxmoxのフォーラムでも言及されています。

IP Address duplicates/conflicts when cloning from a template | Proxmox Support Forum

簡単に説明すると、VMをクローンする際Proxmoxは新しいMACアドレスを割り当てますが、クローンされたVMは同じmachine-idが設定されているので同じIPを要求してしまいます。

フォーラムに解決方法も書いてあるので、k8s2で実行しましょう。

$ sudo rm -f /etc/machine-id && sudo dbus-uuidgen --ensure=/etc/machine-id && sudo rm /var/lib/dbus/machine-id && sudo dbus-uuidgen --ensure

ホスト名も変更

$ sudo hostnamectl set-hostname k8s2

SSHのホストキーも再生成しておきます。

$ sudo rm -f /etc/ssh/ssh_host_*
$ sudo dpkg-reconfigure openssh-server 

設定が終わったらRebootして再ログインしてみましょう。ホスト名とIPが変更されていることを確認します。

うまく変更されていれたら同じ設定をk8s3の方にも適用しておきます。

7. k8s2,3のk8s1のノードに設定する

ここからはコピペができないとだいぶつらいのでSSH経由で

ノードを追加するクラスター(今回はk8s1)でmicrok8s add-nodeコマンドを実行します。

$ microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join 192.168.100.142:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd

Use the '--worker' flag to join a node as a worker not running the control plane, eg:
microk8s join 192.168.100.142:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd --worker

If the node you are adding is not reachable through the default interface you can use one of the following:
microk8s join 192.168.100.142:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd
microk8s join fdfa:750d:b43d:1:be24:11ff:fef3:7c72:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd

ノードを追加するための3つの選択肢が出てきました。

1つ目はフルノードとして追加されます。つまりコントロールプレーンも実行されるということですね。脳みそが複数あるキングギドラをみたいにしたい場合はこちら。

From the node you wish to join to this cluster, run the following:
microk8s join 192.168.100.142:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd

2つ目はワーカーノードとして追加されます。ワーカーノードはコンテナを実行するためのノードなので、ほとんどの場合これで十分です。

Use the '--worker' flag to join a node as a worker not running the control plane, eg:
microk8s join 192.168.100.142:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd --worker

3つ目は複数のNICを持っている場合、別のIPでアクセスできるようにするためのもので、今回の場合だと不要です。

If the node you are adding is not reachable through the default interface you can use one of the following:
microk8s join 192.168.100.142:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd
microk8s join fdfa:750d:b43d:1:be24:11ff:fef3:7c72:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd

k8s2で2つ目のmicrok8s join 192.168.100.142:25000/a17cfad31f0f977c6c57a80a243da890/355581782afd --workerを実行します。

k8s3で実行するコマンドはk8s1で再度add-nodeを実行してから行いましょう。

エラーが出なければ上手く追加できていると思うので、kubectl get nodesを実行し、ノードが追加されたか確認します。

$ kubectl get nodes
NAME     STATUS     ROLES    AGE   VERSION
k8s1     Ready      <none>   40m   v1.32.9
k8s2     Ready      <none>   36s   v1.32.9
k8s3     Ready      <none>   5s    v1.32.9
ubuntu   NotReady   <none>   72m   v1.32.9

私の環境だとホスト名が「ubuntu」だった頃にmicrok8sをインストールしてしまったのでubuntuというノードがNotReadyで生えてしまいました。

不要なので削除します。

$ microk8s remove-node ubuntu

$ kubectl get nodes
NAME   STATUS   ROLES    AGE     VERSION
k8s1   Ready    <none>   46m     v1.32.9
k8s2   Ready    <none>   6m20s   v1.32.9
k8s3   Ready    <none>   5m49s   v1.32.9

これでK8s環境の準備は完了です。

試してみる

Kubernetesの公式チュートリアルで使用されているguestbookというのをデプロイしてみましょう。

kubernetes.io

Redisをデプロイします。

$ kubectl apply -f https://k8s.io/examples/application/guestbook/redis-leader-deployment.yaml

Podを見てみましょう。

$ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
redis-leader-5f4cc9b47d-t2drd   1/1     Running   0          18s

どのノードで実行されているかもみるには-o wideオプションを使用します。

$ kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP           NODE   NOMINATED NODE   READINESS GATES
redis-leader-5f4cc9b47d-t2drd   1/1     Running   0          41s   10.1.219.2   k8s3   <none>           <none>

k8s3で動いてるのがわかりましたね。

どんどん行きましょう。

$ kubectl apply -f https://k8s.io/examples/application/guestbook/redis-leader-service.yaml

$ kubectl get services
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes     ClusterIP   10.152.183.1    <none>        443/TCP    83m
redis-leader   ClusterIP   10.152.183.56   <none>        6379/TCP   7s


$ kubectl apply -f https://k8s.io/examples/application/guestbook/redis-follower-deployment.yaml

$ kubectl get pods -o wide
NAME                              READY   STATUS    RESTARTS   AGE     IP            NODE   NOMINATED NODE   READINESS GATES
redis-follower-854f6dcbd5-lbwkj   1/1     Running   0          29s     10.1.109.66   k8s2   <none>           <none>
redis-follower-854f6dcbd5-njfbr   1/1     Running   0          29s     10.1.219.3    k8s3   <none>           <none>
redis-leader-5f4cc9b47d-t2drd     1/1     Running   0          3m50s   10.1.219.2    k8s3   <none>           <none>

$ kubectl apply -f https://k8s.io/examples/application/guestbook/redis-follower-service.yaml

$ kubectl get services
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes       ClusterIP   10.152.183.1     <none>        443/TCP    85m
redis-follower   ClusterIP   10.152.183.216   <none>        6379/TCP   3s
redis-leader     ClusterIP   10.152.183.56    <none>        6379/TCP   2m37s

$ kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml

$ kubectl get pods -l app=guestbook -l tier=frontend -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE   NOMINATED NODE   READINESS GATES
frontend-7c457c988c-9vlt7   1/1     Running   0          83s   10.1.219.4     k8s3   <none>           <none>
frontend-7c457c988c-gm8ld   1/1     Running   0          83s   10.1.109.67    k8s2   <none>           <none>
frontend-7c457c988c-ldh64   1/1     Running   0          83s   10.1.166.196   k8s1   <none>           <none>

$ kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml

$ kubectl get services
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
frontend         ClusterIP   10.152.183.252   <none>        80/TCP     3s
kubernetes       ClusterIP   10.152.183.1     <none>        443/TCP    87m
redis-follower   ClusterIP   10.152.183.216   <none>        6379/TCP   2m5s
redis-leader     ClusterIP   10.152.183.56    <none>        6379/TCP   4m39s

必要なアプリケーションとサービスを作成できました。get pods を確認するとk8s1~3のノードで動いてるのが確認できたと思います。

最後にサービスにポートフォワードしてアプリケーションにアクセスできるか確認しましょう。

注意:ローカルの8080とServiceの80番ポートをポートフォワードしているので、このコマンドはローカルマシンで実行する必要があります。

$ kubectl port-forward svc/frontend 8080:80

http://localhost:8080にアクセスするとデプロイしたアプリケーションが確認できます。

おわり

microk8sで簡単にK8sを実行できました。今回はUbuntu上で簡単に構築できるmicork8sを使用しましたが、k3sを使っても簡単にK8sクラスターを構築できます。ご興味があれば試してみるのがいいかもしれません。 minikubeやkindはローカルで動かすのには最適ですが、複数クラスターで設定するとなると???やり方を知りません。