開発者ドキュメント

Ubuntu20.04でKubeadmを使用してKubernetesクラスターを作成する方法

序章

Kubernetes は、コンテナーを大規模に管理するコンテナーオーケストレーションシステムです。 Kubernetesは、コンテナを本番環境で実行した経験に基づいてGoogleが最初に開発したもので、オープンソースであり、世界中のコミュニティによって積極的に開発されています。

注:このチュートリアルでは、この記事の公開時点でサポートされている公式バージョンであるバージョン1.22のKubernetesを使用しています。 最新バージョンの最新情報については、Kubernetesの公式ドキュメントの最新リリースノートを参照してください。

Kubeadm は、APIサーバー、コントローラーマネージャー、KubeDNSなどのKubernetesコンポーネントのインストールと構成を自動化します。 ただし、ユーザーを作成したり、オペレーティングシステムレベルの依存関係のインストールとその構成を処理したりすることはありません。 これらの予備的なタスクには、AnsibleSaltStackなどの構成管理ツールを使用できます。 これらのツールを使用すると、追加のクラスターの作成や既存のクラスターの再作成がはるかに簡単になり、エラーが発生しにくくなります。

このガイドでは、AnsibleとKubeadmを使用してKubernetesクラスターを最初からセットアップし、コンテナー化されたNginxアプリケーションをデプロイします。

目標

クラスタには、次の物理リソースが含まれます。

コントロールプレーンノード(Kubernetesの node はサーバーを指します)は、クラスターの状態を管理する役割を果たします。 Etcd を実行し、ワーカーノードへのワークロードをスケジュールするコンポーネント間でクラスターデータを格納します。

ワーカーノードは、ワークロード(つまり コンテナ化されたアプリケーションとサービス)が実行されます。 作業者は、割り当てられた後もワークロードを実行し続けます。スケジュールが完了するとコントロールプレーンがダウンした場合でも同様です。 ワーカーを追加することで、クラスターの容量を増やすことができます。

このガイドを完了すると、クラスター内のサーバーにアプリケーションが消費するのに十分なCPUおよびRAMリソースがあれば、コンテナー化されたアプリケーションを実行する準備が整います。 Webアプリケーション、データベース、デーモン、コマンドラインツールなど、ほとんどすべての従来のUnixアプリケーションをコンテナ化して、クラスター上で実行することができます。 クラスタ自体は、各ノードで約300〜500MBのメモリと10% ofのCPUを消費します。

クラスターをセットアップしたら、Webサーバー Nginx をクラスターにデプロイして、ワークロードが正しく実行されていることを確認します。

前提条件

注:このチュートリアルに従う前に、これらの各サーバーにSSHで接続したことがない場合は、後で不便なときにホストのフィンガープリントを受け入れるように求められることがあります。 今すぐこれを行う必要があります。または、代わりに、ホストキーチェックを無効にすることができます。

ステップ1—ワークスペースディレクトリとAnsibleインベントリファイルを設定する

このセクションでは、ワークスペースとして機能するディレクトリをローカルマシンに作成します。 Ansibleをローカルで構成して、リモートサーバーと通信してコマンドを実行できるようにします。 それが完了したら、サーバーのIPアドレスや各サーバーが属するグループなどのインベントリ情報を含むhostsファイルを作成します。

3台のサーバーのうち、1台はcontrol_plane_ipとして表示されるIPを持つコントロールプレーンになります。 他の2つのサーバーはワーカーであり、IPworker_1_ipworker_2_ipを持ちます。

ローカルマシンのホームディレクトリに~/kube-clusterという名前のディレクトリを作成し、その中にcdを作成します。

  1. mkdir ~/kube-cluster
  2. cd ~/kube-cluster

このディレクトリは、チュートリアルの残りの部分のワークスペースになり、すべてのAnsibleプレイブックが含まれます。 また、すべてのローカルコマンドを実行するディレクトリにもなります。

nanoまたはお気に入りのテキストエディタを使用して、~/kube-cluster/hostsという名前のファイルを作成します。

  1. nano ~/kube-cluster/hosts

次のテキストをファイルに追加します。これにより、クラスターの論理構造に関する情報が指定されます。

〜/ kube-cluster / hosts
[control_plane]
control1 ansible_host=control_plane_ip ansible_user=root 

[workers]
worker1 ansible_host=worker_1_ip ansible_user=root
worker2 ansible_host=worker_2_ip ansible_user=root

[all:vars]
ansible_python_interpreter=/usr/bin/python3

Ansibleのインベントリファイルは、コマンドを実行するための単一のユニットとしてターゲットとするIPアドレス、リモートユーザー、サーバーのグループなどのサーバー情報を指定するために使用されることを思い出してください。 ~/kube-cluster/hostsがインベントリファイルになり、クラスターの論理構造を指定する2つのAnsibleグループ(コントロールプレーンワーカー)を追加しました。

コントロールプレーングループには、コントロールプレーンのIP(control_plane_ip)を一覧表示し、Ansibleがrootユーザーとしてリモートコマンドを実行するように指定する「control1」という名前のサーバーエントリがあります。

同様に、 workers グループには、ansible_userをルートとして指定するワーカーサーバー用の2つのエントリ(worker_1_ipworker_2_ip)があります。

ファイルの最後の行は、AnsibleにリモートサーバーのPython3インタープリターを管理操作に使用するように指示しています。

テキストを追加したら、ファイルを保存して閉じます。 nanoを使用している場合は、Ctrl+Xを押し、プロンプトが表示されたらYEnterを押します。

グループを使用してサーバーインベントリを設定したら、オペレーティングシステムレベルの依存関係のインストールと構成設定の作成に進みましょう。

手順2—すべてのリモートサーバーでroot以外のユーザーを作成する

このセクションでは、すべてのサーバーでsudo権限を持つ非rootユーザーを作成し、非特権ユーザーとして手動でサーバーにSSH接続できるようにします。 これは、たとえば、top/htopなどのコマンドを使用してシステム情報を表示したり、実行中のコンテナーのリストを表示したり、rootが所有する構成ファイルを変更したりする場合に役立ちます。 これらの操作はクラスターの保守中に日常的に実行され、そのようなタスクにroot以外のユーザーを使用すると、重要なファイルを変更または削除したり、意図せずに他の危険な操作を実行したりするリスクを最小限に抑えることができます。

ワークスペースに~/kube-cluster/initial.ymlという名前のファイルを作成します。

  1. nano ~/kube-cluster/initial.yml

次に、次の play をファイルに追加して、すべてのサーバーでsudo権限を持つ非rootユーザーを作成します。 Ansibleでのプレイは、特定のサーバーとグループを対象として実行されるステップのコレクションです。 次の再生では、root以外のsudoユーザーが作成されます。

〜/ kube-cluster / initial.yml
---
- hosts: all
  become: yes
  tasks:
    - name: create the 'ubuntu' user
      user: name=ubuntu append=yes state=present createhome=yes shell=/bin/bash

    - name: allow 'ubuntu' to have passwordless sudo
      lineinfile:
        dest: /etc/sudoers
        line: 'ubuntu ALL=(ALL) NOPASSWD: ALL'
        validate: 'visudo -cf %s'

    - name: set up authorized keys for the ubuntu user
      authorized_key: user=ubuntu key="{{item}}"
      with_file:
        - ~/.ssh/id_rsa.pub

このプレイブックの機能の内訳は次のとおりです。

テキストを追加したら、ファイルを保存して閉じます。

次に、プレイブックをローカルで実行します。

  1. ansible-playbook -i hosts ~/kube-cluster/initial.yml

コマンドは2〜5分以内に完了します。 完了すると、次のような出力が表示されます。

Output
PLAY [all] **** TASK [Gathering Facts] **** ok: [control1] ok: [worker1] ok: [worker2] TASK [create the 'ubuntu' user] **** changed: [control1] changed: [worker1] changed: [worker2] TASK [allow 'ubuntu' user to have passwordless sudo] **** changed: [control1] changed: [worker1] changed: [worker2] TASK [set up authorized keys for the ubuntu user] **** changed: [worker1] => (item=ssh-rsa AAAAB3...) changed: [worker2] => (item=ssh-rsa AAAAB3...) changed: [control1] => (item=ssh-rsa AAAAB3...) PLAY RECAP **** control1 : ok=4 changed=3 unreachable=0 failed=0 worker1 : ok=4 changed=3 unreachable=0 failed=0 worker2 : ok=4 changed=3 unreachable=0 failed=0

事前設定が完了したので、Kubernetes固有の依存関係のインストールに進むことができます。

ステップ3—Kubernetetesの依存関係をインストールする

このセクションでは、Ubuntuのパッケージマネージャーを使用して、Kubernetesに必要なオペレーティングシステムレベルのパッケージをインストールします。 これらのパッケージは次のとおりです。

ワークスペースに~/kube-cluster/kube-dependencies.ymlという名前のファイルを作成します。

  1. nano ~/kube-cluster/kube-dependencies.yml

次の再生をファイルに追加して、これらのパッケージをサーバーにインストールします。

〜/ kube-cluster / kube-dependencies.yml
---
- hosts: all
  become: yes
  tasks:
   - name: create Docker config directory
     file: path=/etc/docker state=directory

   - name: changing Docker to systemd driver
     copy:
      dest: "/etc/docker/daemon.json"
      content: |
        {
        "exec-opts": ["native.cgroupdriver=systemd"]
        }

   - name: install Docker
     apt:
       name: docker.io
       state: present
       update_cache: true

   - name: install APT Transport HTTPS
     apt:
       name: apt-transport-https
       state: present

   - name: add Kubernetes apt-key
     apt_key:
       url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
       state: present

   - name: add Kubernetes' APT repository
     apt_repository:
      repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
      state: present
      filename: 'kubernetes'

   - name: install kubelet
     apt:
       name: kubelet=1.22.4-00
       state: present
       update_cache: true

   - name: install kubeadm
     apt:
       name: kubeadm=1.22.4-00
       state: present

- hosts: control_plane
  become: yes
  tasks:
   - name: install kubectl
     apt:
       name: kubectl=1.22.4-00
       state: present
       force: yes

プレイブックの最初のプレイは次のことを行います。

2番目のプレイは、コントロールプレーンノードにkubectlをインストールする単一のタスクで構成されます。

注: Kubernetesのドキュメントでは、ご使用の環境に最新の安定したリリースのKubernetesを使用することを推奨していますが、このチュートリアルでは特定のバージョンを使用しています。 これにより、Kubernetesは急速に変化し、最新バージョンがこのチュートリアルで機能しない可能性があるため、手順を正常に実行できるようになります。 「xenial」はUbuntu16.04の名前であり、このチュートリアルはUbuntu 20.04を対象としていますが、KubernetesはデフォルトでUbuntu 16.04パッケージソースを参照しており、この場合は20.04でサポートされています。

終了したら、ファイルを保存して閉じます。

次に、次のコマンドを使用して、プレイブックをローカルで実行します。

  1. ansible-playbook -i hosts ~/kube-cluster/kube-dependencies.yml

完了すると、次のような出力が表示されます。

Output
PLAY [all] **** TASK [Gathering Facts] **** ok: [worker1] ok: [worker2] ok: [control1] TASK [create Docker config directory] **** changed: [control1] changed: [worker1] changed: [worker2] TASK [changing Docker to systemd driver] **** changed: [control1] changed: [worker1] changed: [worker2] TASK [install Docker] **** changed: [control1] changed: [worker1] changed: [worker2] TASK [install APT Transport HTTPS] ***** ok: [control1] ok: [worker1] changed: [worker2] TASK [add Kubernetes apt-key] ***** changed: [control1] changed: [worker1] changed: [worker2] TASK [add Kubernetes' APT repository] ***** changed: [control1] changed: [worker1] changed: [worker2] TASK [install kubelet] ***** changed: [control1] changed: [worker1] changed: [worker2] TASK [install kubeadm] ***** changed: [control1] changed: [worker1] changed: [worker2] PLAY [control1] ***** TASK [Gathering Facts] ***** ok: [control1] TASK [install kubectl] ****** changed: [control1] PLAY RECAP **** control1 : ok=11 changed=9 unreachable=0 failed=0 worker1 : ok=9 changed=8 unreachable=0 failed=0 worker2 : ok=9 changed=8 unreachable=0 failed=0

このプレイブックを実行すると、Docker、kubeadm、およびkubeletがすべてのリモートサーバーにインストールされます。 kubectlは必須コンポーネントではなく、クラスターコマンドの実行にのみ必要です。 kubectlコマンドはコントロールプレーンからのみ実行するため、このコンテキストでは、コントロールプレーンノードにのみインストールするのが理にかなっています。 ただし、kubectlコマンドは、任意のワーカーノードから、またはクラスターを指すようにインストールおよび構成できる任意のマシンから実行できることに注意してください。

これで、すべてのシステム依存関係がインストールされました。 コントロールプレーンノードを設定し、クラスターを初期化してみましょう。

ステップ4—コントロールプレーンノードの設定

このセクションでは、コントロールプレーンノードを設定します。 ただし、プレイブックを作成する前に、クラスターに両方が含まれるため、ポッドポッドネットワークプラグインなどのいくつかの概念を説明する価値があります。

ポッドは、1つ以上のコンテナを実行するアトミックユニットです。 これらのコンテナは、ファイルボリュームやネットワークインターフェイスなどのリソースを共有します。 ポッドはKubernetesのスケジューリングの基本単位です。ポッド内のすべてのコンテナは、ポッドがスケジュールされているのと同じノードで実行されることが保証されています。

各ポッドには独自のIPアドレスがあり、あるノードのポッドは、ポッドのIPを使用して別のノードのポッドにアクセスできる必要があります。 単一ノード上のコンテナは、ローカルインターフェイスを介して簡単に通信できます。 ただし、ポッド間の通信はより複雑であり、あるノードのポッドから別のノードのポッドにトラフィックを透過的にルーティングできる別個のネットワークコンポーネントが必要です。

この機能は、ポッドネットワークプラグインによって提供されます。 このクラスターでは、安定したパフォーマンスの高いオプションであるフランネルを使用します。

ローカルマシンでcontrol-plane.ymlという名前のAnsibleプレイブックを作成します。

  1. nano ~/kube-cluster/control-plane.yml

次のプレイをファイルに追加して、クラスターを初期化し、Flannelをインストールします。

〜/ kube-cluster / control-plane.yml
---
- hosts: control_plane
  become: yes
  tasks:
    - name: initialize the cluster
      shell: kubeadm init --pod-network-cidr=10.244.0.0/16 >> cluster_initialized.txt
      args:
        chdir: $HOME
        creates: cluster_initialized.txt

    - name: create .kube directory
      become: yes
      become_user: ubuntu
      file:
        path: $HOME/.kube
        state: directory
        mode: 0755

    - name: copy admin.conf to user's kube config
      copy:
        src: /etc/kubernetes/admin.conf
        dest: /home/ubuntu/.kube/config
        remote_src: yes
        owner: ubuntu

    - name: install Pod network
      become: yes
      become_user: ubuntu
      shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml >> pod_network_setup.txt
      args:
        chdir: $HOME
        creates: pod_network_setup.txt

このプレイの内訳は次のとおりです。

終了したら、ファイルを保存して閉じます。

次のコマンドを使用して、プレイブックをローカルで実行します。

  1. ansible-playbook -i hosts ~/kube-cluster/control-plane.yml

完了すると、次のような出力が表示されます。

Output
PLAY [control1] **** TASK [Gathering Facts] **** ok: [control1] TASK [initialize the cluster] **** changed: [control1] TASK [create .kube directory] **** changed: [control1] TASK [copy admin.conf to user's kube config] ***** changed: [control1] TASK [install Pod network] ***** changed: [control1] PLAY RECAP **** control1 : ok=5 changed=4 unreachable=0 failed=0

コントロールプレーンノードのステータスを確認するには、次のコマンドを使用してSSHで接続します。

  1. ssh ubuntu@control_plane_ip

コントロールプレーンノード内に入ったら、次を実行します。

  1. kubectl get nodes

次の出力が表示されます。

Output
NAME STATUS ROLES AGE VERSION control1 Ready control-plane,master 51s v1.22.4

注: Ubuntu 20.04の時点で、kubernetesは古い用語を更新中です。 このチュートリアル全体でcontrol-planeと呼んでいるノードは、以前はmasterノードと呼ばれていましたが、互換性の理由から、kubernetesが両方の役割を同時に割り当てている場合があります。

出力は、control-planeノードがすべての初期化タスクを完了し、Ready状態にあり、そこからワーカーノードの受け入れとAPIサーバーに送信されたタスクの実行を開始できることを示します。 これで、ローカルマシンからワーカーを追加できます。

ステップ5—ワーカーノードの設定

クラスタにワーカーを追加するには、それぞれに対して1つのコマンドを実行する必要があります。 このコマンドには、コントロールプレーンのAPIサーバーのIPアドレスとポート、およびセキュアトークンなどの必要なクラスター情報が含まれます。 セキュアトークンを渡すノードのみがクラスターに参加できます。

ワークスペースに戻り、workers.ymlという名前のプレイブックを作成します。

  1. nano ~/kube-cluster/workers.yml

次のテキストをファイルに追加して、ワーカーをクラスターに追加します。

〜/ kube-cluster / workers.yml
---
- hosts: control_plane
  become: yes
  gather_facts: false
  tasks:
    - name: get join command
      shell: kubeadm token create --print-join-command
      register: join_command_raw

    - name: set join command
      set_fact:
        join_command: "{{ join_command_raw.stdout_lines[0] }}"


- hosts: workers
  become: yes
  tasks:
    - name: join cluster
      shell: "{{ hostvars['control1'].join_command }} >> node_joined.txt"
      args:
        chdir: $HOME
        creates: node_joined.txt

プレイブックの機能は次のとおりです。

終了したら、ファイルを保存して閉じます。

次のコマンドを使用して、ローカルでプレイブックを実行します。

  1. ansible-playbook -i hosts ~/kube-cluster/workers.yml

完了すると、次のような出力が表示されます。

Output
PLAY [control1] **** TASK [get join command] **** changed: [control1] TASK [set join command] ***** ok: [control1] PLAY [workers] ***** TASK [Gathering Facts] ***** ok: [worker1] ok: [worker2] TASK [join cluster] ***** changed: [worker1] changed: [worker2] PLAY RECAP ***** control1 : ok=2 changed=1 unreachable=0 failed=0 worker1 : ok=2 changed=1 unreachable=0 failed=0 worker2 : ok=2 changed=1 unreachable=0 failed=0

ワーカーノードが追加されたことで、クラスターが完全にセットアップされて機能し、ワーカーがワークロードを実行できるようになりました。 アプリケーションをスケジュールする前に、クラスターが意図したとおりに機能していることを確認しましょう。

ステップ6—クラスターの検証

ノードがダウンしているか、コントロールプレーンとワーカー間のネットワーク接続が正しく機能していないために、セットアップ中にクラスターが失敗することがあります。 クラスタを検証し、ノードが正しく動作していることを確認しましょう。

コントロールプレーンノードからクラスターの現在の状態をチェックして、ノードの準備ができていることを確認する必要があります。 コントロールプレーンノードから切断した場合は、次のコマンドを使用してSSHで接続し直すことができます。

  1. ssh ubuntu@control_plane_ip

次に、次のコマンドを実行して、クラスターのステータスを取得します。

  1. kubectl get nodes

次のような出力が表示されます。

Output
NAME STATUS ROLES AGE VERSION control1 Ready control-plane,master 3m21s v1.22.0 worker1 Ready <none> 32s v1.22.0 worker2 Ready <none> 32s v1.22.0

すべてのノードの値がSTATUSに対してReadyである場合、それらはクラスターの一部であり、ワークロードを実行する準備ができていることを意味します。

ただし、一部のノードでNotReadySTATUSとして使用されている場合は、ワーカーノードがまだセットアップを完了していない可能性があります。 kubectl get nodesを再実行して新しい出力を検査する前に、約5〜10分待ちます。 いくつかのノードでステータスとしてNotReadyがまだ残っている場合は、前の手順でコマンドを確認して再実行する必要がある場合があります。

クラスターが正常に検証されたので、クラスター上でサンプルのNginxアプリケーションをスケジュールしましょう。

ステップ7—クラスターでのアプリケーションの実行

これで、コンテナ化されたアプリケーションをクラスターにデプロイできます。 慣れるために、DeploymentsServicesを使用してNginxをデプロイし、このアプリケーションをクラスターにデプロイする方法を調べてみましょう。 Dockerイメージ名と関連するフラグ(portsvolumesなど)を変更すれば、他のコンテナー化されたアプリケーションにも以下のコマンドを使用できます。

コントロールプレーンノードにログインしていることを確認してから、次のコマンドを実行して、nginxという名前の展開を作成します。

  1. kubectl create deployment nginx --image=nginx

デプロイはKubernetesオブジェクトの一種であり、クラスターの存続期間中にポッドがクラッシュした場合でも、定義されたテンプレートに基づいて指定された数のポッドが常に実行されるようにします。 上記のデプロイでは、Dockerレジストリの Nginx DockerImageから1つのコンテナーでポッドが作成されます。

次に、次のコマンドを実行して、アプリを公開するnginxという名前のサービスを作成します。 これは、 NodePort を介して行われます。これは、クラスターの各ノードで開かれた任意のポートを介してポッドにアクセスできるようにするスキームです。

  1. kubectl expose deploy nginx --port 80 --target-port 80 --type NodePort

サービスは、クラスター内部サービスを内部と外部の両方のクライアントに公開する別のタイプのKubernetesオブジェクトです。 また、複数のポッドへのリクエストの負荷分散も可能であり、Kubernetesの不可欠なコンポーネントであり、他のコンポーネントと頻繁にやり取りします。

次のコマンドを実行します。

  1. kubectl get services

このコマンドは、次のようなテキストを出力します。

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1d nginx NodePort 10.109.228.209 <none> 80:nginx_port/TCP 40m

上記の出力の強調表示された行から、Nginxが実行されているポートを取得できます。 Kubernetesは、30000より大きいランダムなポートを自動的に割り当てますが、ポートが別のサービスによってバインドされていないことを確認します。

すべてが機能していることをテストするには、ローカルマシンのブラウザからhttp://worker_1_ip:nginx_portまたはhttp://worker_2_ip:nginx_portにアクセスします。 Nginxのおなじみのウェルカムページが表示されます。

Nginxアプリケーションを削除する場合は、最初にnginxサービスをコントロールプレーンノードから削除します。

  1. kubectl delete service nginx

以下を実行して、サービスが削除されたことを確認します。

  1. kubectl get services

次の出力が表示されます。

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1d

次に、デプロイメントを削除します。

  1. kubectl delete deployment nginx

以下を実行して、これが機能したことを確認します。

  1. kubectl get deployments
Output
No resources found.

結論

このガイドでは、自動化にKubeadmとAnsibleを使用して、Ubuntu20.04でKubernetesクラスターを正常にセットアップしました。

セットアップが完了したクラスターをどうするか迷っている場合は、次のステップとして、独自のアプリケーションとサービスをクラスターに快適にデプロイできるようにすることをお勧めします。 プロセスをガイドするための詳細情報を含むリンクのリストは次のとおりです。

調べることができるその他の重要な概念は、ボリュームイングレス、およびシークレットです。これらはすべて、実稼働アプリケーションをデプロイするときに役立ちます。

Kubernetesには多くの機能と機能があります。 Kubernetes公式ドキュメントは、概念について学び、タスク固有のガイドを見つけ、さまざまなオブジェクトのAPIリファレンスを検索するのに最適な場所です。 フルスタック開発者向けKubernetesカリキュラムを確認することもできます。

モバイルバージョンを終了