zaki work log

作業ログやら生活ログやらなんやら

[Ansible] kubernetesコネクションプラグインとインベントリプラグインを使ってみる

本エントリは、Ansible Advent Calendar 2023の14日目の記事です。煽られて(?)即席で書き上げました。

昨年共著で出版させていただいたAnsibleクックブックでは紙面の都合 * で掲載しなかった、kubernetesコネクションプラグインについて簡単に使い方の例を簡単に紹介します。
( * 本の趣旨が主に「『プレイブック』の紹介」だったため笑)

kubernetesコネクションプラグイン

まず「コネクションプラグイン」とは、Ansibleがマネージドノード(自動化対象のノード)へ接続する際のプロトコルなどの接続メソッドを指します。デフォルトはsshで、「AnsibleはSSHPythonがあれば使える」のSSHの部分がこれに当たります。
Ansibleクックブックのコンテナの章「5-1-4 コネクションプラグイン」では「Dockerコネクションプラグイン」については簡単に解説しており、これは実行中のコンテナに対してSSHを使わずに docker exec のようにコンテナ内のコマンドを直接実行する機能を使ってAnsibleを自動化処理を送り込むことができます。(コンテナ内にPythonインタプリタは必要)

kubernetesコネクションプラグインは、KubernetesのPodに対する接続を行うためのプラグインで、Pod(の中のコンテナ)に対してSSH接続を行わずにkubectl execのようにコマンドを直接実行する機能を使ってAnsibleの自動化処理を行います。(これもDockerのケース同様、コンテナ内にPythonインタプリタは必要)

docs.ansible.com

なお、実行にはkubectlコマンドが実行ノードに必要です。

基本

インベントリファイルで、ansible_connectionにコネクションプラグインの指定と、ansible_kubectl_kubeconfig変数でKubernetesクラスタ接続用のKUBECONFIGファイルの指定を行います。
また、マネージドノードにはPod名を指定します。ネームスペースやコンテナ名(1Podに複数コンテナ構成の場合)も同様に指定します。
(以下はグループ変数でなくホスト変数としてネームスペース指定)

[pods]
awx-demo-web-f88868474-7qxsl ansible_kubectl_namespace=awx ansible_kubectl_container=awx-demo-web

[all:vars]
ansible_connection=kubectl
ansible_kubectl_kubeconfig=/home/zaki/local/src/ansible-sample/k8s-module/connection/k3s.yaml

インベントリは上記の通りで、例として以下のPlaybookを使ってコンテナ内のファイル一覧を取得してみます。

---
- hosts: all
  gather_facts: false

  tasks:
    - name: get filelist
      command: ls /var/lib/awx

実行結果は以下の通り、SSH接続せずにコンテナのファイル一覧を取得できました。

$ ansible-playbook -i inventory.ini command.yml -v
Using /home/zaki/local/src/ansible-sample/k8s-module/connection/ansible.cfg as config file

PLAY [all] **********************************************************************************************************

TASK [get filelist] *************************************************************************************************
changed: [awx-demo-web-f88868474-7qxsl] => changed=true 
  ansible_facts:
    discovered_interpreter_python: /usr/bin/python3
  cmd:
  - ls
  - /var/lib/awx
  delta: '0:00:00.002655'
  end: '2023-12-13 13:51:03.222642'
  msg: ''
  rc: 0
  start: '2023-12-13 13:51:03.219987'
  stderr: ''
  stderr_lines: <omitted>
  stdout: |-
    awxfifo
    public
    rsyslog
    venv
  stdout_lines: <omitted>

PLAY RECAP **********************************************************************************************************
awx-demo-web-f88868474-7qxsl : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

実際にkubectl execで確認した結果は以下の通り。

zaki@k3s-node1:~$ kubectl exec -it -n awx awx-demo-web-f88868474-7qxsl -c awx-demo-web -- bash
bash-5.1$ ls /var/lib/awx/
awxfifo  public  rsyslog  venv
bash-5.1$

Pod名の指定 (12/14追記)

前述のインベントリファイルではマネージドノードのホスト名としてPod名を指定しましたが、ansible_kubectl_pod変数を使っても指定できます。
こんな感じ

[pods]
awx-web ansible_kubectl_pod=awx-demo-web-f88868474-7qxsl ansible_kubectl_container=awx-demo-web ansible_kubectl_namespace=awx 

コンテキストの指定

よくあるパターンとして~/.kube/configには複数クラスタの情報がストアされており、デフォルトにセットされているクラスタでなく特定のクラスタを指定したい場合…というよりCLIで使ってる状態に依存させたくない場合は、ansible_kubectl_contextでコンテキストを指定します。

[pods]
awx-demo-web-f88868474-7qxsl ansible_kubectl_namespace=awx ansible_kubectl_container=awx-demo-web

[all:vars]
ansible_connection=kubectl
ansible_kubectl_context=local-k3s
ansible_kubectl_kubeconfig=/home/zaki/.kube/config

クラスタ名と現在のクラスタkubectl config get-contextsで確認可能です。

zaki-hmkc.hatenablog.com

k8sインベントリプラグイン (コネクションプラグインとの組み合わせは動作未確認)

docs.ansible.com

kubernetesコネクションプラグインを使った接続は、インベントリでPod名を固定で指定する必要があります。Deploymentなどから…というかStatefulSet以外から生成されるPodは名称がランダムになるため、インベントリファイルにスタティックに記述するには都合が悪い場合があります。
そういうときはダイナミックインベントリを使ってPod名を動的に取得できる……と思ってたんだけど、試してみると「Pod名のみ」でなく「Pod名コンテナ名」として取得してしまうため、kubernetesコネクションプラグインとのコンボは現状難しそう。。 接続のためのPod名は、hostvarsに ansible_kubectl_pod としてセットされるので、「Pod名コンテナ名」を接続情報として利用できそう。コネクションプラグインの指定も含まれます。(12/14追記、動作未確認)

一応使い方を書いておくと、、、

基本

---
plugin: kubernetes.core.k8s
connections:
  - kubeconfig: /home/zaki/local/src/ansible-sample/k8s-module/connection/work/kubeconfig.yaml
    context: default
    namespaces:
    - awx

このインベントリファイルを使ってansible-inventory --graphを実行すると、「pod名_コンテナ名」の書式でnamespaceだけでなく、ラベルを使った様々なグループでKubernetesクラスタ上のPodとServiceの情報を得ることができます。
実行結果を抜粋するとこの通り。

$ ansible-inventory  -i inventory.yaml --graph
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
@all:
  |--@ungrouped:

[...]

  |--@label_app.kubernetes.io/part-of_awx-demo:
  |  |--awx-demo-postgres-13-0_postgres
  |  |--awx-demo-task-585bb4c956-kb59d_awx-demo-ee
  |  |--awx-demo-task-585bb4c956-kb59d_awx-demo-rsyslog
  |  |--awx-demo-task-585bb4c956-kb59d_awx-demo-task
  |  |--awx-demo-task-585bb4c956-kb59d_redis
  |  |--awx-demo-web-f88868474-7qxsl_awx-demo-rsyslog
  |  |--awx-demo-web-f88868474-7qxsl_awx-demo-web
  |  |--awx-demo-web-f88868474-7qxsl_redis
  |  |--awx-demo-postgres-13
  |  |--awx-demo-service

[...]

  |--@label_app.kubernetes.io/name_awx-demo-web:
  |  |--awx-demo-web-f88868474-7qxsl_awx-demo-rsyslog
  |  |--awx-demo-web-f88868474-7qxsl_awx-demo-web
  |  |--awx-demo-web-f88868474-7qxsl_redis

[...]

ちなみにkubectl get pod -n awx --show-labelsを実行すると以下の通り。
awx-demo-web-f88868474-7qxslを得るにはapp.kubernetes.io/name=awx-demo-webを目印に取得することができる。

$ kubectl get pod -n awx --show-labels
NAME                                               READY   STATUS    RESTARTS   AGE   LABELS
awx-operator-controller-manager-6c55dc66bd-kjnln   2/2     Running   0          79m   control-plane=controller-manager,pod-template-hash=6c55dc66bd
awx-demo-postgres-13-0                             1/1     Running   0          78m   app.kubernetes.io/component=database,app.kubernetes.io/instance=postgres-13-awx-demo,app.kubernetes.io/managed-by=awx-operator,app.kubernetes.io/name=postgres-13,app.kubernetes.io/part-of=awx-demo,controller-revision-hash=awx-demo-postgres-13-85958bcbcd,statefulset.kubernetes.io/pod-name=awx-demo-postgres-13-0
awx-demo-task-585bb4c956-kb59d                     4/4     Running   0          77m   app.kubernetes.io/component=awx,app.kubernetes.io/managed-by=awx-operator,app.kubernetes.io/name=awx-demo-task,app.kubernetes.io/operator-version=2.7.2,app.kubernetes.io/part-of=awx-demo,app.kubernetes.io/version=23.4.0,pod-template-hash=585bb4c956
awx-demo-web-f88868474-7qxsl                       3/3     Running   0          76m   app.kubernetes.io/component=awx,app.kubernetes.io/managed-by=awx-operator,app.kubernetes.io/name=awx-demo-web,app.kubernetes.io/operator-version=2.7.2,app.kubernetes.io/part-of=awx-demo,app.kubernetes.io/version=23.4.0,pod-template-hash=f88868474

なお、実行にはkubernetesPythonパッケージが必要。(pip install kubernetesでインストールする)

使いどころ

Kubernetesの基本としては、Podをデプロイしてその中身を後から変更する、というのはあまりよい使い方ではないですが、Podとしてデプロイしたアプリケーションに対するAPI操作をAnsibleで行うような場合に、ServiceやIngressを使って外部向けにHTTPS公開している経路ではなく、KubernetesAPIサーバー経由でPod内のシェルを使って内部からHTTPアクセスする、という使い方ができます。

具体的には、AWXのようなwebアプリケーションをマネージドKubernetesで動かしている場合に、クラウドサービスのアプリケーションゲートウェイ経由のアクセスでなく、kubectlを実行しているホストからawxモジュールを使ったAWX上のリソース作成を自動化したりできます。


Kubernetesのカレンダークロスポストできないかチェックしてみたけど、今日は空いてなかった…残念(笑)