モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

複数の物理ホストの Debian9 上に Kubernetes (k8s) クラスタを Rancher で立ち上げる

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2018/10/31
最終更新最終更新
2022/06/07
記事区分記事区分
一般公開

目次

    仕事では Kubernetesの運用を中心に、GitLabとの連携も担当するインフラエンジニア。

    Docker オーケストレーションツールの一つに Kubernetes (k8s) があります。k8s 実行環境の構築方法は複数ありますが、ここでは AWS や GCP 等のクラウドサービスを利用せず、Debian9 がインストールされた複数台の物理マシンがネットワーク内に存在する状況を考えます。これら複数の Debian9 上に k8s クラスタを立ち上げるためには Rancher が利用できます。k8s 以外の用途で利用しないことが分かっている場合は、Debian9 上で Rancher を利用するのではなく専用の RancherOS を利用することもできます。

    ホストマシンの用意

    ここでは実験のため VirtualBox で二つの Debian9 マシンを起動して、それらを同じ NAT ネットワーク 10.0.2.0/24 に所属させます。

    • debian1 10.0.2.4/24
    • debian2 10.0.2.5/24

    各ホストマシンへの Rancher のインストール

    簡単のため Docker イメージとして提供される Rancher を利用します。Docker エンジンをインストールします。

    sudo apt-get update
    sudo apt-get install \
         apt-transport-https \
         ca-certificates \
         curl \
         gnupg2 \
         software-properties-common
    curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
    sudo add-apt-repository \
       "deb [arch=amd64] https://download.docker.com/linux/debian \
       $(lsb_release -cs) \
       stable"
    sudo apt-get update
    sudo apt-get install docker-ce
    

    sudo なしで docker コマンドを利用できるように設定できます。

    sudo groupadd docker
    sudo usermod -aG docker $USER
    exit # ログインしなおし
    docker ps
    

    以下のコマンドで Rancher を起動します。データを永続化するための -v、および後に Node 追加のために起動する rancher-agent コンテナへのポート割り当てを考慮した -p を指定します。

    docker run -d --name=rancher --restart=unless-stopped \
      -v /host/rancher:/var/lib/rancher \
      -p 8080:80 \
      -p 8443:443 \
      rancher/rancher:stable
    

    ブラウザからアクセスして admin の初期パスワードを設定してログインします https://127.0.0.1:8080

    $ docker ps
    CONTAINER ID  IMAGE                   COMMAND          CREATED         STATUS         PORTS                                     NAMES
    cc89ae5eac4a  rancher/rancher:stable  "entrypoint.sh"  28 minutes ago  Up 28 minutes  0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp  rancher
    

    Rancher Server URL にはホスト名など、ネットワーク内の他のマシンおよびローカルからアクセスできるものを指定します。更に必要な場合は nginx 等でリバースプロキシ設定を行います。X-Forwarded-Proto を指定することで、Rancher 側では http から https へのリダイレクトを行わなくなります。

    Rancher で k8s クラスタを立ち上げる

    ブラウザから「Add Cluster」→「CUSTOM」→「Cluster Name: mycluster」→「Next」として k8s クラスタの設定を追加します。

    k8s クラスタに追加する Node を起動するための docker run コマンドを生成するためのオプションとして「etcd, Control, Worker」すべてにチェックを入れると以下のようなコマンドが表示されます。

    sudo docker run -d --privileged --restart=unless-stopped --net=host -v /etc/kubernetes:/etc/kubernetes -v /var/run:/var/run rancher/rancher-agent:v2.1.1 --server https://10.0.2.4:8443 --token 9c5p642z52p7tllfjzc2hgfwkb5xmck6266vdlvs82lfc8crwbbsd6 --ca-checksum a42937938e0c38ba4e56845260c8105017205e886677fa0c6c5d020bf6a9ed93 --etcd --controlplane --worker
    

    これを Rancher を起動したホストで実行すると、同じ Debian マシン上に Rancher サーバコンテナに加えて、Rancher-agent コンテナおよびその他必要なコンテナが起動した状態になります。

    $ docker ps | awk '{ print $2 }' | grep rancher | sort | uniq
    rancher/coreos-etcd:v3.2.18
    rancher/hyperkube:v1.11.3-rancher1
    rancher/metrics-server-amd64
    rancher/pause-amd64:3.1
    rancher/rancher:stable
    

    同様に別の Debian マシンで上記コマンドによって Rancher-agent を起動して Rancher サーバに接続することで、クラスタに Node を追加できます。以下の画像は debian1 10.0.2.4/24 と debian2 10.0.2.5/24 で Node 数が 2 の状態です。Node の追加が正常に完了するまでは Alert が表示された状態になります。

    k8s クラスタで Docker コンテナを走らせる

    k8s クラスタで Docker コンテナを走らせるためには、Rancher の WebUI および HTTP API に加えて、標準の kubectl コマンドも利用できます。kubectl は Rancher ではなく k8s 標準のコマンドです。クラスタを複数台のマシン間で組む必要がない場合は microk8sminikube を利用すると、ローカルマシン上に k8s クラスタを比較的簡単に構築でき、kubectl コマンドの動作確認等が行えます。以下では Rancher で起動した k8s クラスタを kubectl から利用するコマンドサンプルを記載します。

    kubectl コマンドのインストール

    kubectl は k8s クラスタのクライアントコマンドです。OS に応じて apt、yum、brew 等でインストールできます。Debian9 の場合は以下のようになります。

    sudo apt-get update && sudo apt-get install -y apt-transport-https
    curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
    echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
    sudo apt-get update
    sudo apt-get install -y kubectl
    

    補足: バイナリをダウンロードする方法

    curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
    

    Web UI から取得したサーバへの接続情報を ~/.kube/config にコピーして接続確認します。kubectl クライアントと k8s クラスタのバージョンは Minor の一つ違いまで動作することが保証されています。例えば v1.2 クライアントは v1.1, v1.2, v1.3 クラスタに対して利用できます。

    $ kubectl cluster-info
    Kubernetes master is running at https://192.168.56.11:8443/k8s/clusters/c-zt2l5
    KubeDNS is running at https://192.168.56.11:8443/k8s/clusters/c-zt2l5/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    
    To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    
    $ kubectl version
    Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.2", GitCommit:"17c77c7898218073f14c8d573582e8d2313dc740", GitTreeState:"clean", BuildDate:"2018-10-24T06:54:59Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
    Server Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T17:53:03Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
    

    また、Rancher の WebUI に実装されている簡易シェルからも kubectl コマンドが利用できます。

    k8s クラスタについて

    k8s クラスタは複数のコンポーネントで構成されます。コンポーネントはクラスタを構成するマシン上で実行されます。これらマシンを Node とよびます。k8s は実行するコンポーネントを etcd、Control Plane、Worker の三つのロールに分けて管理しており、上記の通り Node となる各マシンで rancher/rancher-agent を docker run するときの --etcd --controlplane --worker オプションで選択できるようになっています。"Node" という表現が重複しますが、コンポーネントを Master コンポーネントと Node コンポーネントで分けた場合において、etcd は Master コンポーネントに分類されます。

    • etcd → クラスタ内の分散 KVS です。
    • Control Plane → スケジューラや API サーバの機能を提供します。クラスタの状態はすべて etcd が管理するためステートレスなコンポーネントです。
    • Worker → ユーザアプリケーションを実行します。

    Worker で実行するユーザアプリケーションは Pod という単位で管理されます。Pod は一つ以上の Docker コンテナおよび必要となるファイル等から成ります。Worker では複数の Pod を同時に実行できます。Worker には Kubelet というプロセスが常駐しており、コンテナの状態等を監視します。

    nginx コンテナを起動して HTTP サービスを公開する例

    クラスタ内のノードを確認

    kubectl get nodes
    
    NAME      STATUS   ROLES                      AGE   VERSION
    debian1   Ready    controlplane,etcd,worker   6d    v1.11.3
    debian2   Ready    controlplane,etcd,worker   5d    v1.11.3
    

    クラスタ内に Pod のデプロイ設定を登録して Pod を起動 (kubectl run)

    設定ファイルを基本とした kubectl create によるクラスタ操作の方法と、設定ファイルを用いない kubectl run による方法があります。状況に応じてメリットとデメリットを考慮しながら使い分けます

    kubectl run mydeployment --image=nginx
    kubectl get deployments
    kubectl describe deployments
    
    NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    mydeployment   1         1         1            1           3m
    

    自動的にデプロイ設定に応じた Pod も作成されます。

    kubectl get pods
    kubectl describe pods
    
    NAME                            READY   STATUS    RESTARTS   AGE
    mydeployment-65b9f8795d-r4hrs   1/1     Running   0          4m
    

    デプロイにサービスポートを設定

    kubectl expose deployment/mydeployment --type="NodePort" --port 80
    kubectl get services
    kubectl describe services
    
    NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
    kubernetes     ClusterIP   10.43.0.1      <none>        443/TCP        10d  ←k8s作成時から存在
    mydeployment   NodePort    10.43.89.123   <none>        80:31685/TCP   6s  ←今回新規作成
    

    nginx のサービスを利用してみます。

    kubectl cluster-info 
    curl 192.168.56.11:31685
    

    NAT の外部 IP は以下のコマンドで取得できます。

    kubectl get services/mydeployment -o go-template='{{(index .spec.ports 0).nodePort}}'
    

    削除

    サービス

    kubectl delete services mydeployment
    

    デプロイ (Pod も合わせて削除されます)

    kubectl delete deployments mydeployment
    kubectl get pods
    
    NAME                            READY   STATUS        RESTARTS   AGE
    mydeployment-65b9f8795d-r4hrs   0/1     Terminating   0          12m
    

    コマンドサンプル

    Pod 内のログを確認

    Pod 名の確認

    kubectl get pods -o wide
    
    NAME                            READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE
    mydeployment-65b9f8795d-8r4pl   1/1     Running   0          16m   10.42.0.8    debian   <none>
    

    tailf のように監視できます。

    kubectl logs mydeployment-65b9f8795d-8r4pl -f
    

    すべて削除

    Pod 削除が完了するまで待つ

    kubectl delete services,deployments,jobs,pods,cronjobs --all
    

    Terminate されたことの確認を待たない

    kubectl delete services,deployments,jobs,pods,cronjobs --all --grace-period 0 --force
    

    Pod 一覧の取得

    echo "kubectl get pods -o go-template --template '[[range .items]][[.metadata.name]][[\"\\n\"]][[end]]'" | tr '[' '{' | tr ']' '}'
    
    mydeployment-65b9f8795d-vb72j
    mydeployment2-6dcc9fb68-9gbbs
    
    kubectl get pods -o name
    
    pod/mydeployment-65b9f8795d-vb72j
    pod/mydeployment2-6dcc9fb68-9gbbs
    

    起動済みの Pod に対してコマンドを発行

    -c を指定しない場合は Pod 内のコンテナが一つ選択されます。

    kubectl exec -it mydeployment-65b9f8795d-dpt96 /bin/bash
    kubectl exec mydeployment-65b9f8795d-dpt96 -- ls /
    kubectl exec mydeployment-65b9f8795d-dpt96 -- /bin/bash -c "ls && ls"
    

    クラスタ内への HTTP プロキシを一時的に立てる

    kubectl proxy --port 8001
    curl http://localhost:8001/
    

    Rancher から利用する場合は /k8s/clusters/ を付けます。例えば API OVERVIEW に記載の namespaces 一覧を取得する例は以下のようになります。

    curl http://127.0.0.1:8001/k8s/clusters/<CLUSTER_ID>/api/v1/namespaces
    

    kubectl run のオプション

    環境変数の設定

    kubectl run mydeployment --image=nginx --env="MYENV1=xxx" --env="MYENV2=yyy"
    kubectl exec mydeployment-6c6b59798f-2bqp4 -- /bin/bash -c 'echo $MYENV1'
    

    イメージのコマンドを上書き

    kubectl run mydeployment --image=nginx --restart=Never -it --command -- /bin/bash -c "ls /"
    kubectl run mydeployment --image=nginx --restart=Never -it --command -- /bin/bash
    

    --restart=Never を付与すると Pod のみ作成されます。デプロイ設定は作成されません。

    kubectl run mydeployment --image=nginx --restart=Never
    kubectl get pods
    kubectl get deployments
    

    Pod のみを create する YAML

    Deployment や Job を利用せず直接 Pod だけを create できます。

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      containers:
      - image: nginx
        name: nginx
      restartPolicy: Never
    
    $ kubectl get pods
    NAME    READY   STATUS    RESTARTS   AGE
    mypod   1/1     Running   0          15s
    

    cron ジョブ

    kubectl run mydeployment --image=nginx --restart=Never --schedule="0/2 * * * *" --command -- /bin/bash -c "date"
    kubectl get cronjobs
    kubectl delete cronjobs --all
    
    NAME           SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
    mydeployment   0/2 * * * *   False     0        <none>          20s
    

    デプロイ設定は作成されません。

    $ kubectl get deployments
    No resources found.
    
    $ kubectl get pods
    NAME                            READY   STATUS      RESTARTS   AGE
    mydeployment-1542640920-rhphc   0/1     Completed   0          8s
    
    $ kubectl logs mydeployment-1542640920-rhphc
    Mon Nov 19 15:22:14 UTC 2018
    

    kubectl create で設定する YAML/JSON を kubectl run で設定

    例えば --cap-add ALL --privileged--name xxx-h yyy に相当する設定は以下のようになります--env で指定した環境変数の値は無視されるため JSON 内に記載します。以下では特権モードにした状態でホストのデバイスファイルをマウントしています。

    kubectl run mydeployment --image=nginx --overrides '{
      "spec": {
        "template": {
          "spec": {
            "hostname": "yyy",
            "containers": [
              {
                "name": "xxx",
                "image": "nginx",
                "env": [
                  {"name":"MYENV", "value":"zzz"}
                ],
                "securityContext": {
                  "capabilities": {
                    "add": ["ALL"]
                  },
                  "privileged": true
                },
                "volumeMounts": [
                  {
                    "mountPath": "/dev/fuse",
                    "name": "devfuse"
                  }
                ]
              }
            ],
            "volumes": [
              {
                "name": "devfuse",
                "hostPath": {
                  "path": "/dev/fuse"
                }
              }
            ]
          }
        }
      }
    }'
    
    kubectl exec -it `kubectl get pods -l run=mydeployment -o name | cut -d/ -f2` -- /bin/bash -c 'hostname'
    yyy
    
    kubectl exec -it `kubectl get pods -l run=mydeployment -o name | cut -d/ -f2` -- /bin/bash -c 'ls -l /dev/fuse'
    crw-rw-rw- 1 root root 10, 229 Sep  7 08:28 /dev/fuse
    
    kubectl exec -it `kubectl get pods -l run=mydeployment -o name | cut -d/ -f2` -- /bin/bash -c 'echo $MYENV'
    zzz
    
    kubectl describe pods -l run=mydeployment | grep -A1 Containers:
    Containers:
      xxx:
    

    docker の ENTRYPOINT は command で変更できます。CMD は args で指定できます。

    kubectl run mydeployment --image=nginx --overrides '{
      "spec": {
        "template": {
          "spec": {
            ...
            "containers": [
              {
                ...
                "command": ["/bin/bash", "-c"],
                "args": ["echo 123 && echo 123"]
              }
            ],
    

    既定では imagePullPolicyIfNotPresent になっているため、:latest タグを指定している場合等を除いて、既に同名のイメージが Node 上に存在する場合は pull されませんAlways を指定することでこれを回避できます。

    "image": "nginx",
    "imagePullPolicy": "Always",
    ...
    

    特定のデバイスファイルを隠したい場合

    ホスト側のデバイスファイルを利用したい場合があります。docker の --device オプションに相当する機能が k8s で利用できない場合--privileged全デバイスファイルの利用を許可するしかありません。デバイスファイルのうち一部を隠したい場合は、以下のように設定できます。hostPath で FileOrCreate を指定しています。

    kubectl run mydeployment --image=nginx --overrides '{
      "spec": {
        "template": {
          "spec": {
            "hostname": "yyy",
            "containers": [
              {
                "name": "xxx",
                "image": "nginx",
                "env": [
                  {"name":"MYENV", "value":"zzz"}
                ],
                "securityContext": {
                  "capabilities": {
                    "add": ["ALL"]
                  },
                  "privileged": true
                },
                "volumeMounts": [
                  {
                    "mountPath": "/dev/fuse",
                    "name": "devfuse"
                  },
                  {
                    "mountPath": "/dev/port",
                    "name": "devport"
                  }
                ]
              }
            ],
            "volumes": [
              {
                "name": "devfuse",
                "hostPath": {
                  "path": "/dev/fuse"
                }
              },
              {
                "name": "devport",
                "hostPath": {
                  "path": "/dev/shm/mydevport_mydeployment",
                  "type": "FileOrCreate"
                }
              }
            ]
          }
        }
      }
    }'
    

    ラベルの利用

    Pod とサービスを作成します。

    kubectl run mydeployment --image=nginx
    kubectl expose deployment/mydeployment --type="NodePort" --port 80
    

    -lkey=value 形式のラベルに合致する Pod およびサービスを選択できます。

    kubectl get deployments -l run=mydeployment
    kubectl get pods -l run=mydeployment
    kubectl get services -l run=mydeployment
    

    追加のラベルを付与するためには以下のようにします。

    kubectl label pod mydeployment-65b9f8795d-f67s7 mykey=myvalue
    kubectl get pods -l mykey=myvalue
    

    ラベルを指定した削除も行えます。

    kubectl delete service -l run=mydeployment
    kubectl delete deployments -l run=mydeployment
    

    Pod 内のコンテナへのファイル転送および取得

    Pod を作成します。

    kubectl run mydeployment --image=nginx
    

    ファイルを転送します。-c でコンテナを指定できます。

    echo 'hello' > /tmp/hello.txt
    kubectl cp /tmp/hello.txt mydeployment-65b9f8795d-z7b9d:/tmp/
    kubectl exec mydeployment-65b9f8795d-z7b9d -- cat /tmp/hello.txt
    

    ディレクトリも転送できます。

    mkdir /tmp/mydir
    echo 'hello' > /tmp/mydir/hello1.txt
    echo 'hello' > /tmp/mydir/hello2.txt
    kubectl cp /tmp/mydir mydeployment-65b9f8795d-z7b9d:/tmp/
    kubectl exec mydeployment-65b9f8795d-z7b9d -- ls /tmp/mydir/
    

    取得は以下のようになります。

    mkdir /tmp/mydir2
    kubectl cp mydeployment-65b9f8795d-z7b9d:/tmp/mydir /tmp/mydir2
    

    一時的なポート転送

    Pod を作成します。

    kubectl run mydeployment --image=nginx
    

    Pod 内の 80 番を localhost の 8080 で Listen するようにポート転送します。

    kubectl port-forward mydeployment-65b9f8795d-d7n66 8080:80
    curl localhost:8080
    

    デプロイ設定に対しても実行できます。

    kubectl port-forward deployment/mydeployment 8080:80
    

    CPU/メモリ 使用量の調査

    Node マシン

    kubectl top node
    kubectl top node debian1
    

    Pod 毎

    kubectl top pod -l run=mydeployment
    

    コンテナ間通信

    Pod 内のコンテナはネットワークを共有するため、お互いのサービスに localhost:xxxx でアクセスできます。異なる Pod 内のコンテナとの通信については、Rancher の場合、各 Pod に割り当てられた Rancher managed IP を指定して通信できます。既定では managed ネットワーク 10.42.0.0/16 から各 Pod に ip が割り当てられます。

    kubectl exec -it mydeployment-65b9f8795d-5qwtf -- /bin/bash
    apt update
    apt install iproute2
    ip addr
    
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    3: eth0@if181: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
        link/ether 0a:a4:0d:10:28:38 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 10.42.0.84/32 scope global eth0
           valid_lft forever preferred_lft forever
    

    また別の方法として kubectl expose でサービスを作成し、サービスに ClusterIP を割り当てることで、背後の Pod にアクセスをプロキシして通信することもできます。Rancher の場合は既定では 10.43.0.0/16 が指定できます。

    kubectl expose deployment/mydeployment --cluster-ip 10.43.0.123 --port=8080 --container-port=80
    kubectl get services
    curl 10.43.0.123:8080
    
    NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    kubernetes     ClusterIP   10.43.0.1     <none>        443/TCP    24m
    mydeployment   ClusterIP   10.43.0.123   <none>        8080/TCP   23m
    

    NodePort で利用するポート番号を指定

    以下のコマンドでテンプレートを作成できます。

    kubectl expose deployment/mydeployment --type="NodePort" --port 80 --cluster-ip 10.43.0.101 --port=22,80,5900 --dry-run -o yaml
    

    出力された YAML を編集して nodePort の設定を追加できます。

    ...
    spec:
      ...
      ports:
      - name: ssh
        port: 22
        protocol: TCP
        targetPort: 22
        nodePort: 30022
      ...
    

    expose ではなく create を利用してサービスを作成します。

    kubectl create -f /path/to/my.yaml
    

    YAML 設定ファイルに関するコマンド

    新規作成

    kubectl create -f nginx.yaml
    kubectl create -f configs/
    

    再作成

    kubectl replace -f nginx.yaml
    

    削除

    kubectl delete -f nginx.yaml -f redis.yaml
    

    ネームスペース

    一覧取得

    kubectl get namespaces
    

    YAML から作成

    apiVersion: v1
    kind: Namespace
    metadata:
      name: mynamespace
    

    リソースタイプに関する説明を表示

    kubectl explain pods
    

    クラスタ内のイベントを表示

    時系列順にクラスタ内でのイベントを表示できます。デバッグ等で役立ちます。

    kubectl get events --sort-by=.metadata.creationTimestamp
    

    kubectl サブコマンドの登録

    v1.12 以上の kubectl で利用できるプラグイン機能を利用すると、実行ファイルをサブコマンドとして登録できます。パスの通ったディレクトリに kubectl- で始まるファイルを設置するだけで利用できます。

    kubectl-xxx-yyy

    #!/bin/bash
    
    echo ok
    

    パスの通ったディレクトリに設置

    chmod +x kubectl-xxx-yyy 
    sudo mv kubectl-xxx-yyy /usr/local/bin/
    

    実行例

    $ kubectl xxx yyy
    ok
    

    プラグインの確認

    $ kubectl plugin list
    The following kubectl-compatible plugins are available:
    
    /usr/local/bin/kubectl-xxx-yyy
    

    特定の Node で起動

    xxxx というホスト名の Node で起動させたい場合は kubernetes.io/hostname を設定します。

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      containers:
      - image: nginx
        name: nginx
      restartPolicy: Never
      nodeSelector:
        kubernetes.io/hostname: xxxx
    

    コンテナで利用できる CPU/Memory保証および制限

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      containers:
      - image: nginx
        name: nginx
        resources:
          requests:
            cpu: 0.0
            memory: 1024Mi
          limits:
            cpu: 1.0
            memory: 1024Mi
      restartPolicy: Never
    

    正しく設定されていることを確認します。

    $ kubectl describe pods | grep Limits -A5
        Limits:
          cpu:     1
          memory:  1Gi
        Requests:
          cpu:        0
          memory:     1Gi
    

    要求したリソースを持つ Node が存在しない場合はスケジューリングに失敗します。

    $ kubectl get events --sort-by=.metadata.creationTimestamp
    ...
    Warning   FailedScheduling   default-scheduler   0/1 nodes are available: 1 Insufficient memory.
    

    Pod IP を引けるように DNS 登録 (headless service)

    clusterIP を None に設定した Service を作成して Pod に向けることで、Service 名が Pod の IP に解決されるような DNS レコードを登録できます。このような Service を Headless service とよびます。Headless service の ports には仮のものを設定します。

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      containers:
      - image: nginx
        name: nginx
      restartPolicy: Never
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: myheadless
      name: myheadless
    spec:
      clusterIP: None
      selector:
        run: mypod
      ports:
      - name: myheadless
        port: 1
    

    Headless service 名で Pod の IP が取得できていることが分かります。Headless service 名を Pod 名と同じにすることもできます。

    kubectl -it exec mypod /bin/bash
    apt update && apt install dnsutils
    
    root@mypod:/# dig +short +search myheadless
    10.42.0.70
    root@mypod:/# dig +short +search mypod | wc -l
    0
    root@mypod:/# cat /etc/hosts | grep 10.
    10.42.0.70      mypod
    

    設定ファイルをコンテナにマウント

    ConfigMap を利用すると、設定ファイルをコンテナ内にマウントできます。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: myconfig
    data:
      myconfig.yml: |
        xxx: 123
        yyy: 123
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: config-volume
          mountPath: /mnt/etc/
      volumes:
      - name: config-volume
        configMap:
          name: myconfig
      restartPolicy: Never
    

    確認

    $ kubectl -it exec mypod /bin/bash
    root@mypod:/# cat /mnt/etc/myconfig.yml 
    xxx: 123
    yyy: 123
    

    /etc/hosts ファイルに追記

    hostAliases を設定することでコンテナ内の /etc/hosts にエントリを追加できます。

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      containers:
      - image: nginx
        name: nginx
      restartPolicy: Never
      hostAliases:
      - ip: 1.2.3.4
        hostnames:
        - xxx.example.com
        - yyy.example.com
    

    設定の確認

    $ kubectl -it exec mypod -- cat /etc/hosts
    # Kubernetes-managed hosts file.
    127.0.0.1       localhost
    ::1     localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    fe00::0 ip6-mcastprefix
    fe00::1 ip6-allnodes
    fe00::2 ip6-allrouters
    10.42.0.76      mypod
    
    # Entries added by HostAliases.
    1.2.3.4 xxx.example.com
    1.2.3.4 yyy.example.com
    

    WebUI の設定

    Kubernetes 公式のクラスタ管理用 WebUI が存在します。手動インストールもできますが、Rancher で利用するためにはカタログからインストールすると簡単です。作成したクラスタの kube-system ネームスペースに存在する Catalog Apps タブを開いて kubernetes-dashboard をインストールします。その際 IMPORTANT: Enable Dashboard Cluster Admin Role*True に設定する必要があります。

    インストールが完了すると secret が追加されます

    $ kubectl -n kube-system get secret | grep dashboard
    kubernetes-dashboard                             Opaque                                0      13s
    kubernetes-dashboard-key-holder                  Opaque                                2      13h
    kubernetes-dashboard-token-bqsh8                 kubernetes.io/service-account-token   3      13s
    

    token を確認します。

    $ kubectl -n kube-system describe secret kubernetes-dashboard-token-bqsh8 | grep token:
    token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC10b2tlbi1icXNoOCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImNjOTAxMjk3LTA3NDUtMTFlOS04Y2E5LTA4MDAyNzA4MTczOSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTprdWJlcm5ldGVzLWRhc2hib2FyZCJ9.tepB_K8BlyPc6gqmlw8xLkBgPlbzq-K5PAsQZ2hq1CCeqffFSoQ1AqVeMMyLqQdJmf2FAUN7eit3WoXenS8q1pJGYerX_rBr_MY2QhkMvlBCpulqjT0Ss5fenfKPk4V5Cxwk9zYGe8skyaWtGFiVlz4rz0qtt-jAm7qBPZuVXYvZIGTHuYOlRm0wnf37V4SnsMeDashcJ-JWfGJynchIiF1k36U7g_Z3VjJJSMIeQZhsw-RF4pr-JAzhQ3VZLwvioP-XNhbVSzqmGju3IHIYw992VBj9zaY9HKOg8VW9Ix7U29U2shnb9q6isvNEheL3p3vSB5LpdSt7ca31YREjuw
    

    エンドポイントを確認します。

    ログインすると以下のような画面になります。

    Init Containers による初期化処理

    アプリケーションコンテナ起動前に別のコンテナを起動して初期化処理を行うことができます。

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      volumes:
      - name: shared-volume
        hostPath:
          path: /tmp/shared
          type: DirectoryOrCreate
      initContainers:
      - name: hello-1
        image: debian:stretch
        volumeMounts:
        - name: shared-volume
          mountPath: /shared
        command: ['/bin/bash']
        args: ['-c', 'echo "aaa" > /shared/hello.txt']
      - name: hello-2
        image: debian:stretch
        volumeMounts:
        - name: shared-volume
          mountPath: /shared
        command: ['/bin/chmod']
        args: ['a+rwx', '/shared/hello.txt']
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: shared-volume
          mountPath: /shared
      restartPolicy: Never
    

    初期化処理で作成したファイルがアプリケーションコンテナから参照できる状態にあることが分かります。

    $ kubectl exec mypod -- /bin/bash -c 'ls -l /shared'
    total 4
    -rwxrwxrwx 1 root root 4 Dec 27 16:08 hello.txt
    $ kubectl exec mypod -- /bin/bash -c 'cat /shared/hello.txt'
    aaa
    

    L7 ロードバランサ (Ingress)

    k8s の Ingress リソースを利用すると HTTP リバースプロキシで Service を外部に公開できます。AWS ALB に相当する L7 ロードバランサであるため、HTTP/HTTPS 以外の L4 ロードバランサとしては利用できません。Rancher の実装において Ingress は Nginx です

    kubectl create -f xxx.yml
    kubectl describe ingresses
    

    以下のように YAML で定義できます。

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: myingress
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      rules:
      - host: localhost
        http:
          paths:
          - path: /mypath
            backend:
              serviceName: myservice
              servicePort: 80
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: mypod
      name: mypod
    spec:
      containers:
      - image: nginx
        name: nginx
      restartPolicy: Never
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: myservice
      name: myservice
    spec:
      clusterIP: None
      selector:
        run: mypod
      ports:
      - name: myservice
        protocol: TCP
        port: 80
        targetPort: 80
    

    Ingress は Node マシンの 80 および 443 を利用します。同じマシンでマスターとなる Rancher と Rancher Agent を両方とも起動する場合は、マスターとなる Rancher が利用するポート番号を 80 および 443 から変更する必要があることに注意します。

    Prometheus 連携

    Prometheusnode-exporterDaemonSet で各 Node に設置した場合等は Prometheus の設定で kubernetes_sd_configs の記載が必要になります。role: node を利用するためには namespace 毎に存在する default Service Account では権限が不足するため https://127.0.0.1:8001/apikeys で Rancher API トークンを発行する必要があります。発行したトークンの利用確認は以下のようなコマンドで行えます。

    curl -sS -k -H "Authorization: Bearer token-f6rdl:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://127.0.0.1:8001/k8s/clusters/c-xxxxx/api/v1/nodes
    

    こちらのページを参考にしながら Prometheus 設定を行います。Rancher API を経由するため公式ドキュメントに記載の api_server 等を設定する必要があります。また relabel_config を用いて prometheus node exporter のホスト名等を書き換えることができます。Grafanaを Import すると簡単です。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: prometheus
    data:
      prometheus.yml: |
        global:
          scrape_interval: '15s'
        scrape_configs:
          - job_name: 'prometheus'
            static_configs:
              - targets: ['localhost:9090']
          - job_name: 'k8s-nodes'
            kubernetes_sd_configs:
            - role: node
              api_server: https://127.0.0.1:8001/k8s/clusters/c-xxxxx
              bearer_token: token-f6rdl:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
              tls_config:
                insecure_skip_verify: true
            relabel_configs:
            - source_labels: [__meta_kubernetes_node_name]
              regex: (.+)
              target_label: __address__
              replacement: ${1}:9100
            - action: labelmap
              regex: __meta_kubernetes_node_label_(.+)
    

    latest タグのイメージの Deployment Pod を無停止更新

    非推奨ですが、latest タグが付与された docker イメージを利用している Deployment の Pod を再作成したいことがあります。

    サービスが停止しても良い場合は Pod を削除すると Deployment によって新しい Pod が再作成されます。新しい Pod を作成する際に latest イメージが docker pull されます。

    kubectl delete pods xxxxx-yyyyyy
    

    サービスの無停止更新を行いたい場合は以下のように kubectl patch を利用できます。イメージタグの代わりに metadata を現在時刻のタイムスタンプで書き換えています。

    kubectl patch deployment xxxxx -p "{\"spec\": {\"template\": {\"metadata\": {\"labels\": {\"date\": \"$(date +'%s')\" }}}}}"
    

    v1.15 以降であれば以下のコマンドが利用できます。

    kubectl rollout restart deployment xxxxx
    
    Likeボタン(off)0
    詳細設定を開く/閉じる
    アカウント プロフィール画像

    仕事では Kubernetesの運用を中心に、GitLabとの連携も担当するインフラエンジニア。

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事