Jaybanuan's Blog

調べたことをメモしていくブログ

Kubernetesの自習用の情報源

コンテナを利用したHTML動作確認用のテストWebサーバ

はじめに

静的なHTMLファイルの動作確認は、基本的にはローカルに保存した.htmlファイルをブラウザに読み込ませればよい。 ただし、XMLHttpRequestやFetch APIを利用した非同期通信を行っている場合は、テスト用のWebサーバを準備しないとテストできない。 そのため、コンテナを利用してテスト用のWebサーバを立ち上げることにした。

環境

# cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 20.04.1 LTS"

# docker --version
Docker version 19.03.13, build 4484c46d9d

テスト用Webサーバの起動と停止

初回の起動は以下のコマンドを実行する。 /path/to/srcは環境によって変えること。

# docker run --name test-web-server -v /path/to/src/:/usr/share/nginx/html:ro -d -p 8080:80 nginx

停止は以下のコマンドを実行する。

# docker stop test-web-server

もう一度起動するには、以下を実行するか、

# docker start test-web-server

もしくはコンテナを削除してから、初回の起動と同じコマンドを実行する。

# docker rm test-web-server
# docker run --name test-web-server -v /path/to/src/:/usr/share/nginx/html:ro -d -p 8080:80 nginx

参考

Ubuntu 20.04LTSでMinikubeを構築する

はじめに

Minikubeのマニュアルを読みながら、Ubuntu 20.04LTSでMinikubeを構築したときのメモ。 マニュアルの中身だが、Linuxディストリビューションや仮想化基盤などでいくらか分岐があるので、忘れた頃に読み直すと時間がかかる。 今後のMinikubeの再構築を効率的に行うために、ここでは自分の環境に合わせて一本道になるように、手順を残しておく。

(1) CPUの仮想化テクノロジーのサポートの確認

以下を実行して、何かしら表示が出ればOK。

# grep -E --color 'vmx|svm' /proc/cpuinfo
flags       : fpu vme de pse tsc msr pae mce cx8 (以降省略)

何も表示されない場合は、BIOSで仮想化テクノロジーを有効化するなどの対処が必要になる。

(2) kubectlのインストール

Ubuntu 20.04LTSだとSnapを使うのが一番簡単。

# sudo snap install kubectl --classic

kubectlの動作確認をしておく。

# kubectl version --client
Client Version: version.Info{Major:"1", Minor:"19", (以降省略)

(3) 仮想化基盤の構築

ここではKVMを利用することにする。 他の選択肢としては、VirtualBoxやDockerがある。 KVMの構築については以下のブログを参照。

redj.hatenablog.com

(4) Minikubeのインストール

インストール方法は、単にシングルバイナリをコピーする方法と、各種パッケージ(.debなど)を利用した方法がある。 ただし、執筆時点(2020/10)ではパッケージを利用する方法はまだExperimentalと注意書きがあるので、今回はシングルバイナリを利用する。

# curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
# sudo install minikube /usr/local/bin

(5) 動作確認

(5-1) Minikubeの起動

以下のコマンドを実行すると、(必要なら)ファイルが自動的にダウンロードされて、環境が構築される。

# minikube start --driver=kvm2
😄  Ubuntu 20.04 上の minikube v1.13.1
✨  設定を元に、 kvm2 ドライバを使用します
💾  docker-machine-driver-kvm2 ドライバをダウンロードしています:
    > docker-machine-driver-kvm2.sha256: 65 B / 65 B [-------] 100.00% ? p/s 0s
    > docker-machine-driver-kvm2: 13.81 MiB / 13.81 MiB  100.00% 359.38 KiB p/s
💿  VM ブートイメージをダウンロードしています...
    > minikube-v1.13.1.iso.sha256: 65 B / 65 B [-------------] 100.00% ? p/s 0s
    > minikube-v1.13.1.iso: 173.91 MiB / 173.91 MiB  100.00% 209.31 KiB p/s 14m
👍  コントロールプレーンのノード minikube を minikube 上で起動しています
💾  Kubernetes v1.19.2 のダウンロードの準備をしています
    > preloaded-images-k8s-v6-v1.19.2-docker-overlay2-amd64.tar.lz4: 486.36 MiB
🔥  kvm2 VM (CPUs=2, Memory=3900MB, Disk=20000MB) を作成しています...
🐳  Docker 19.03.12 で Kubernetes v1.19.2 を準備しています...
🔎  Kubernetes コンポーネントを検証しています...
🌟  有効なアドオン: default-storageclass, storage-provisioner
🏄  Done! kubectl is now configured to use "minikube" by default

(5-2) Minikubeの状態の確認

以下のコマンドを実行して、Minikubeの状態を確認する。

# minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

ついでに、VMのリストを表示してみる。

# virsh list
 Id   Name        State
---------------------------
 1    minikube    running

(5-3) Minikubeの停止

# minikube stop
✋  ノード "minikube" を停止しています...
🛑  1台のノードが停止しました。

(6) おまけ - 環境のクリア

以下のコマンドを実行することで、環境はまっさらになるはず。

minikube delete --all --purge
🔥  kvm2 の「minikube」を削除しています...
💀  クラスタ "minikube" の全てのトレースを削除しました。
🔥  Successfully deleted all profiles
💀  Successfully purged minikube directory located at - [/home/jaybanuan/.minikube]

参考

REST APIで見かけるvnd.を含んでいるメディアタイプについて

はじめに

REST APIで時々見かけるメディアタイプで、vnd.を含んでいるものがある。 これが何なのかが気になったので調べた。

vnd.はベンダ固有のメディアタイプ

RFC 6838: Media Type Specifications and Registration Procedures によると、vnd.はベンダーの裁量で決めた独自のサブタイプにつけるプレフィックスらしい。 RFC 6838では、このプレフィックスのことをfacetと呼んでるが、文脈からし名前空間に相当する概念と理解した。 サブタイプがvnd.をから始まっていても、なかにはIANAに公式に登録されているメディアタイプもある。

具体例

GitHubAPIだとapplication/vnd.github+jsonというメディアタイプが利用されている。

参考

Ansibleでの環境変数の設定(/etc/environment)が挙動不審

はじめに

AnsibleのPlaybookで/etc/environmentにプロキシ関連の環境変数(http_proxyとか)を書き込んだ際、書き込んだはずの環境変数が後続のタスクで参照できなかったので調査した。

環境

$ cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 20.04.1 LTS"

$ ansible --version
ansible 2.9.7
  config file = None
  configured module search path = ['/home/redj/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/redj/.local/lib/python3.8/site-packages/ansible
  executable location = /home/redj/.local/bin/ansible
  python version = 3.8.2 (default, Jul 16 2020, 14:00:26) [GCC 9.3.0]

現象

試行 1 - 環境変数が見えない

以下のPlaybookを実行すると、最後のタスクdebughttp_proxyなどが表示されてほしいが、実際には表示されない。

- hosts: target
  tasks:
    - name: /etc/environment にプロキシの環境変数を書き込み
      become: yes
      ini_file:
        path: /etc/environment
        no_extra_spaces: yes
        section: null
        option: "{{ item.key }}"
        value: "{{ item.value }}"
      loop: "{{ proxy_envs | dict2items }}"
      vars:
        proxy_envs:
          http_proxy: http://192.168.8.8:3128/
          https_proxy: http://192.168.8.8:3128/
          no_proxy: 127.0.0.1,localhost
    
    - name: 環境変数の取得
      shell: env | grep "_proxy" | cat
      register: result
      
    - name: 環境変数の表示
      debug:
        var: result.stdout_lines

実行結果は以下のようになり、プロキシ関連の環境変数が見つからないことがわかる。

$ ansible-playbook -i hosts.yml playbook.yml

PLAY [target] **********************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************
ok: [192.168.8.16]

TASK [/etc/environment にプロキシの環境変数を書き込み] ********************************************************************************************
changed: [192.168.8.16] => (item={'key': 'http_proxy', 'value': 'http://192.168.8.8:3128/'})
changed: [192.168.8.16] => (item={'key': 'https_proxy', 'value': 'http://192.168.8.8:3128/'})
changed: [192.168.8.16] => (item={'key': 'no_proxy', 'value': '127.0.0.1,localhost'})

TASK [環境変数の取得] *********************************************************************************************************************
changed: [192.168.8.16]

TASK [環境変数の表示] *********************************************************************************************************************
ok: [192.168.8.16] => {
    "result.stdout_lines": []
}

PLAY RECAP *************************************************************************************************************************
192.168.8.16               : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

試行 2 - 環境変数が見える

試しにもう一度実行してみると、今回は環境変数は見えている。 /etc/environmentの更新がokになっていることから、初回の実行での環境変数の追加は成功していることが分かる。 なぜ初回の実行では環境変数が見えていないんだろうか…。

$ ansible-playbook -i hosts.yml playbook.yml

PLAY [target] **********************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************
ok: [192.168.8.16]

TASK [/etc/environment にプロキシの環境変数を書き込み] ********************************************************************************************
ok: [192.168.8.16] => (item={'key': 'http_proxy', 'value': 'http://192.168.8.8:3128/'})
ok: [192.168.8.16] => (item={'key': 'https_proxy', 'value': 'http://192.168.8.8:3128/'})
ok: [192.168.8.16] => (item={'key': 'no_proxy', 'value': '127.0.0.1,localhost'})

TASK [環境変数の取得] *********************************************************************************************************************
changed: [192.168.8.16]

TASK [環境変数の表示] *********************************************************************************************************************
ok: [192.168.8.16] => {
    "result.stdout_lines": [
        "no_proxy=127.0.0.1,localhost",
        "https_proxy=http://192.168.8.8:3128/",
        "http_proxy=http://192.168.8.8:3128/"
    ]
}

PLAY RECAP *************************************************************************************************************************
192.168.8.16               : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

試行 3 - 環境変数が見える

今度はターゲットのサーバの/etc/environmentを元に戻してやり直してみる。 さらに、Playbookでbecome: yesの位置を以下のようにタスク全体にかかるように移動しておく。

- hosts: target
  become: yes
  tasks:
(以下略)

このPlaybookを実行すると、今度は初回の実行で環境変数が見つかる。 /etc/environmentの更新がchangedになっていることから、環境変数の追加が成功し、かつ後続のタスクで環境変数が見えていることが分かる。 なぜだ…。

$ ansible-playbook -i hosts.yml playbook.yml

PLAY [target] **********************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************
ok: [192.168.8.16]

TASK [/etc/environment にプロキシの環境変数を書き込み] ********************************************************************************************
changed: [192.168.8.16] => (item={'key': 'http_proxy', 'value': 'http://192.168.8.8:3128/'})
changed: [192.168.8.16] => (item={'key': 'https_proxy', 'value': 'http://192.168.8.8:3128/'})
changed: [192.168.8.16] => (item={'key': 'no_proxy', 'value': '127.0.0.1,localhost'})

TASK [環境変数の取得] *********************************************************************************************************************
changed: [192.168.8.16]

TASK [環境変数の表示] *********************************************************************************************************************
ok: [192.168.8.16] => {
    "result.stdout_lines": [
        "no_proxy=127.0.0.1,localhost",
        "https_proxy=http://192.168.8.8:3128/",
        "http_proxy=http://192.168.8.8:3128/"
    ]
}

PLAY RECAP *************************************************************************************************************************
192.168.8.16               : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

解決方法

結論から言うと、Ansibleが呼び出すsshコマンドのパラメータを調整して、Multiplexing (多重化)を無効化することで解決した。

SSHのMultiplexingとは、ひとつのTCPコネクション上に複数のSSHセッションをのせる仕組みのこと。 言い換えるとコネクションを再利用する仕組みであり、これを利用すると都度接続が不要になため、sshコマンドを連発するような場合に高速化が見込める。

つまりこれはAnsibleに適した高速化の仕組みであり、ANSIBLE_SSH_ARGSという設定項目でデフォルトで有効化されている。 以下にマニュアルでのANSIBLE_SSH_ARGSの説明を抜粋する。

項目 説明
Description: If set, this will override the Ansible default ssh arguments. In particular, users may wish to raise the ControlPersist time to encourage performance. A value of 30 minutes may be appropriate. Be aware that if -o ControlPath is set in ssh_args, the control path setting is not used.
Default: -C -o ControlMaster=auto -o ControlPersist=60s
Ini Section: ssh_connection
Ini Key: ssh_args
Environment: ANSIBLE_SSH_ARGS

Multiplexingを無効化するsshのパラメータは?

sshのMultiplexingに関係するパラメータは、主に以下の3つ。 「簡単な説明」は自分なりにまとめたものなので、正確な定義はOpenSSHのマニュアルを参照のこと。

パラメータ 簡単な説明
ControlMaster yesの場合は自身がMasterであることを、noの場合はMasterではない(=クライアントである)ことを示すautoの場合はMasterがいない時には自動的に自身がMasterになる。
ControlPersist クライアントがいなくなってからMasterのコネクションを切断するまでのタイムアウト値。
ControlPath コネクションを共有するためのソケットファイルのパス。noneを指定した場合はMultiplexingを利用しない。

上の表より、sshコマンドラインパラメータとして-o ControlPath=noneを付け加えれば良い。

注意点として、ググると「Multiplexingをオフにするには-o ControlMaster=noとしておけ」みたいな情報があるが、これは「自分はクライアント」と宣言しているのであり、オフになったわけではない。

Ansibleでの設定方法 1 - ANSIBLE_SSH_ARGS

sshのパラメータの「ベース」を指定するANSIBLE_SSH_ARGSに対して-C -o ControlPath=noneを設定する。 ANSIBLE_SSH_ARGSの設定方法は、ansible.cfgで設定する方法と、環境変数で設定する方法の、2パターンある。

ansible.cfgで設定する場合は、以下のようにする。

[ssh_connection]
ssh_args=-C -o ControlPath=none

また、環境変数で設定するには、Ansibleを以下のように実行するか、あるいは~/.profileなどに当該の環境変数を定義しておく。

$ export ANSIBLE_SSH_ARGS="-C -o ControlPath=none"
$ ansible-playbook playbook.yml

Ansibleでの設定方法 2 - ansible_ssh_extra_args

ansible_ssh_extra_argsで指定したsshのパラメータは、ANSIBLE_SSH_ARGSの内容の後ろに追加されてsshに渡される。 ansible_ssh_extra_argsの設定方法は、Ansibleのコマンドラインパラメータとして設定する方法と、インベントリなどでAnsibleの変数として設定する方法の、2パターンある。

Ansibleのコマンドラインパラメータとして設定する場合は、以下のようにAnsibleを実行する。

$ ansible-playbook --ssh-extra-args="-o ControlPath=none" -i hosts.yml playbook

インベントリでAnsibleの変数として設定するには、インベントリを以下のように記述する。

devpc:
  hosts:
    "192.168.8.16":
      ansible_user: jaybanuan
      ansible_ssh_extra_args: -o ControlPath=none

Ansibleでの設定方法 - まとめ

Ansibleでのsshコマンドラインパラメータの指定場所がややこしいので、以下の表にまとめておく。 個人的には、ansible_ssh_extra_argsをAnsibleの変数としてインベントリで定義すると、接続先に柔軟に対応できるためよいと思う。

設定場所 ANSIBLE_SSH_ARGS ansible_ssh_extra_args
ansible.cfg
起動時のパラメータ
環境変数
Ansibleの変数

結局のところ原因は何?

結局はsshのMultiplexingが影響しているという事以外は分からなかった。 sshのMultiplexingに辿り着いたのは、/etc/environmentはログインしなおせば効くはずなのに効いておらず、Multiplexingはクライアントではsshの認証が省略される(のか?)ので、ログアウトしきれていないのでは、と推測したため。

参考

Ubuntuのデフォルトのお気に入り(Favorite Applications)の変更

UbuntuというよりはGNOMEの設定だが、デフォルトのお気に入り(Favorite Applications)の変更方法は以下に記載があった。