zaki work log

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

[Kubernetes / Helm] Helm Chart作成おためし (Getting StartedとNginx Pod作成)

helm.sh

Getting Startedに沿ってやってみる。
ローカル上にあるChartファイルをパス指定してデプロイするまで。
Helm自体のGetting Startedやってから3か月も経っている件…

流れ

  1. helm create <my-chart>でテンプレートを作成する
  2. 不要なテンプレートを削除して必要なテンプレートを作る
  3. helm install <my-release> <my-chart>でデプロイする

ConfigMapのChart作成

テンプレート作成

[zaki@cloud-dev helm-chart]$ helm create mychart
Creating mychart

こんな感じ

[zaki@cloud-dev helm-chart]$ find mychart/
mychart/
mychart/Chart.yaml
mychart/values.yaml
mychart/.helmignore
mychart/templates
mychart/templates/ingress.yaml
mychart/templates/deployment.yaml
mychart/templates/service.yaml
mychart/templates/serviceaccount.yaml
mychart/templates/hpa.yaml
mychart/templates/NOTES.txt
mychart/templates/_helpers.tpl
mychart/templates/tests
mychart/templates/tests/test-connection.yaml
mychart/charts

テンプレート削除

作ったばかりなのに何を言っているんだ感あるけど、チュートリアルとして最小構成にするためいったん削除

[zaki@cloud-dev helm-chart]$ rm -rf mychart/templates/*
[zaki@cloud-dev helm-chart]$ find mychart/
mychart/
mychart/Chart.yaml
mychart/values.yaml
mychart/.helmignore
mychart/templates
mychart/charts

ConfigMapのテンプレートを作成

mychart/templates/configmap.yamlファイルを作成。
内容的にはハードコーディングしてある状態。

apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

デプロイする

作業用namespaceを作って、そこへデプロイしてみる。

[zaki@cloud-dev helm-chart]$ kc create namespace helm-example
namespace/helm-example created
[zaki@cloud-dev helm-chart]$ helm ls -n helm-example
NAME    NAMESPACE       REVISION        UPDATED STATUS  CHART   APP VERSION
[zaki@cloud-dev helm-chart]$ helm install sample ./mychart/ -n helm-example
NAME: sample
LAST DEPLOYED: Mon Sep 14 19:49:21 2020
NAMESPACE: helm-example
STATUS: deployed
REVISION: 1
TEST SUITE: None
[zaki@cloud-dev helm-chart]$ helm ls -n helm-example
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
sample  helm-example    1               2020-09-14 19:49:21.04252068 +0900 JST  deployed        mychart-0.1.0   1.16.0
[zaki@cloud-dev helm-chart]$ kubectl get configmap -n helm-example
NAME                 DATA   AGE
istio-ca-root-cert   1      109s
mychart-configmap    1      19s

Istio入れてるので自動で作成されたConfgiMapがあるけどそれは置いておいて、mychart-configmapの作成を確認。

[zaki@cloud-dev helm-chart]$ kubectl get configmap -n helm-example mychart-configmap -o yaml
apiVersion: v1
data:
  myvalue: Hello World
kind: ConfigMap
metadata:
  annotations:
    meta.helm.sh/release-name: sample
    meta.helm.sh/release-namespace: helm-example
  creationTimestamp: "2020-09-14T10:49:22Z"
  labels:
    app.kubernetes.io/managed-by: Helm
  name: mychart-configmap
  namespace: helm-example
  resourceVersion: "4879814"
  selfLink: /api/v1/namespaces/helm-example/configmaps/mychart-configmap
  uid: 011681a6-ffe1-4252-94f4-7a07cb51a2be

Helmで使用されたテンプレートの確認

[zaki@cloud-dev helm-chart]$ helm get manifest sample -n helm-example
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

変数

テンプレートを以下の内容に変更する。

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"

アップグレードのDry Run

アップグレードするにはhelm upgradeを実行する。
今回は、アップグレードまえにDry Runしてどう変化するか確認する。

[zaki@cloud-dev helm-chart]$ helm upgrade sample ./mychart/ -n helm-example --dry-run
Release "sample" has been upgraded. Happy Helming!
NAME: sample
LAST DEPLOYED: Mon Sep 14 19:52:04 2020
NAMESPACE: helm-example
STATUS: pending-upgrade
REVISION: 2
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-configmap
data:
  myvalue: "Hello World"

[zaki@cloud-dev helm-chart]$

アップグレードする

Dry Runの内容に問題なければアップグレードする。

[zaki@cloud-dev helm-chart]$ helm upgrade sample ./mychart/ -n helm-example
Release "sample" has been upgraded. Happy Helming!
NAME: sample
LAST DEPLOYED: Mon Sep 14 19:53:36 2020
NAMESPACE: helm-example
STATUS: deployed
REVISION: 2
TEST SUITE: None

upgradeすることで、HelmリリースのRevisionも更新された。

[zaki@cloud-dev helm-chart]$ helm ls -n helm-example
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
sample  helm-example    2               2020-09-14 19:53:36.747219418 +0900 JST deployed        mychart-0.1.0   1.16.0
[zaki@cloud-dev helm-chart]$ kubectl get cm -n helm-example
NAME                 DATA   AGE
istio-ca-root-cert   1      6m4s
sample-configmap     1      18s

ConfigMapのオブジェクト名が新しくなっている。

[zaki@cloud-dev helm-chart]$ kubectl get cm -n helm-example sample-configmap -o yaml
apiVersion: v1
data:
  myvalue: Hello World
kind: ConfigMap
metadata:
  annotations:
    meta.helm.sh/release-name: sample
    meta.helm.sh/release-namespace: helm-example
  creationTimestamp: "2020-09-14T10:53:38Z"
  labels:
    app.kubernetes.io/managed-by: Helm
  name: sample-configmap
  namespace: helm-example
  resourceVersion: "4880627"
  selfLink: /api/v1/namespaces/helm-example/configmaps/sample-configmap
  uid: be0a13ec-920c-4c80-9462-a043cda48293

サンプルのNginx PodのChart作成

Chart作成の基本というかコアの部分はわかったので、試しにNginxのテンプレートの最小限の部分を使ってwebサーバーpodを作ってみる。

template

$ helm create sample-web
Creating sample-web

必要なものだけ残して削除。

[zaki@cloud-dev helm-chart]$ find sample-web
sample-web
sample-web/Chart.yaml
sample-web/values.yaml
sample-web/.helmignore
sample-web/templates
sample-web/templates/deployment.yaml
sample-web/templates/service.yaml
sample-web/templates/_helpers.tpl
sample-web/templates/NOTES.txt
sample-web/charts

こんな感じ。

github.com

ちなみにtemplates/_helpers.tplは消しちゃダメ。(後述)

helm install

[zaki@cloud-dev helm-chart]$ kc create ns sample-web
namespace/sample-web created

全部同じ名前だからわかりづらいけど、以下の通り。

  • install sample-webのsample-web: release名
  • ./sample-web/: chartのパス
  • -n sample-web: デプロイ先のnamespace名 (kubectlで指定するのと同じ)
[zaki@cloud-dev helm-chart]$ helm install sample-web ./sample-web/ -n sample-web
NAME: sample-web
LAST DEPLOYED: Mon Sep 14 20:52:02 2020
NAMESPACE: sample-web
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace sample-web -l "app.kubernetes.io/name=sample-web,app.kubernetes.io/instance=sample-web" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace sample-web port-forward $POD_NAME 8080:80

なるほどー、NOTES.txtを用意しておくと、デプロイした時に説明(デプロイした後にどうすればいいのか等)を表示できるのね。

[zaki@cloud-dev helm-chart]$ helm ls -n sample-web
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
sample-web      sample-web      1               2020-09-14 20:52:02.475726571 +0900 JST deployed        sample-web-0.1.0        1.16.0

アクセス確認

[zaki@cloud-dev helm-chart]$ kc get pod,svc -n sample-web
NAME                              READY   STATUS    RESTARTS   AGE
pod/sample-web-5d5dbd4d9c-252wc   1/1     Running   0          33s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/sample-web   ClusterIP   10.96.8.194   <none>        80/TCP    34s

ClusterIPでServiceを作ってるのでkubectl port-forwardでポート転送設定をする。

[zaki@cloud-dev helm-chart]$ export POD_NAME=$(kubectl get pods --namespace sample-web -l "app.kubernetes.io/name=sample-web,app.kubernete
s.io/instance=sample-web" -o jsonpath="{.items[0].metadata.name}")
[zaki@cloud-dev helm-chart]$ echo $POD_NAME
sample-web-5d5dbd4d9c-252wc
[zaki@cloud-dev helm-chart]$ kubectl --namespace sample-web port-forward $POD_NAME 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

シェルをもう1個起動してcurlする。

[zaki@cloud-dev ~]$ curl http://127.0.0.1:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

うごいた。

error

_helpers.tplを消してしまうと、以下のエラーが出るので注意。

[zaki@cloud-dev helm-chart]$ helm install sample-web ./sample-web/ --dry-run
Error: template: sample-web/templates/tests/test-connection.yaml:4:12: executing "sample-web/templates/tests/test-connection.yaml" at <include "sample-web.fullname" .>: error calling include: template: no template "sample-web.fullname" associated with template "gotpl"

ドキュメント

公式のThe Chart Template Developer's Guideの情報量かなり多そう。

helm.sh


参考

qiita.com

IUSリポジトリのパッケージでCentOS 7にGit version 2をインストールした

VS CodeのGitHistoryやGitLens拡張がいつの間にか動かなくなってた。
エラーの通りGit Versionが1系なのが原因なのでアップデートしてみる。

f:id:zaki-hmkc:20200912103920p:plain

こんなエラー

git shortlog -e -s -n HEAD  (completed in 0.008s)
git log --full-history --pretty=oneline --date-order --decorate=full --skip=0 --max-count=100 master --  (completed in 0.015s)
git rev-list --full-history --count master --  (completed in 0.023s)
git show --pretty=oneline --decorate=full --numstat 87662dc26e01e584e2f728ca625010b4323fbc7a  (completed in 0.009s)
git show --name-status --pretty=oneline -M --first-parent 87662dc26e01e584e2f728ca625010b4323fbc7a  (completed in 0.006s)
Unrecognized file stat status 'c

IUSリポジトリの追加

Yumリポジトリリストはこんな感じ

[zaki@cloud-dev ~]$ yum repolist
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.riken.jp
 * epel: ftp.iij.ad.jp
 * extras: ftp.riken.jp
 * updates: ftp.riken.jp
リポジトリー ID               リポジトリー名                                        状態
azure-cli                     Azure CLI                                                 80
base/7/x86_64                 CentOS-7 - Base                                       10,070
docker-ce-stable/x86_64       Docker CE Stable - x86_64                                 79
epel/x86_64                   Extra Packages for Enterprise Linux 7 - x86_64        13,445
extras/7/x86_64               CentOS-7 - Extras                                        413
kubernetes                    Kubernetes                                               561
updates/7/x86_64              CentOS-7 - Updates                                     1,127
repolist: 25,775
[zaki@cloud-dev ~]$ rpm -qa | grep git
git-1.8.3.1-23.el7_8.x86_64
linux-firmware-20191203-76.gite8a0f4c.el7.noarch
crontabs-1.11-6.20121102git.el7.noarch

Git公式のダウンロードページに行くとRHELCentOSについてはこう書かれている。

Red Hat Enterprise Linux, Oracle Linux, CentOS, Scientific Linux, et al.

RHEL and derivatives typically ship older versions of git. You can download a tarball and build from source, or use a 3rd-party repository such as the IUS Community Project to obtain a more recent version of git.

ius.io

IUSなんてあったんだ、知らなかった。
セットアップのページを見ると、RHEL/CentOS7の場合はこの通り。

yum install \
https://repo.ius.io/ius-release-el7.rpm \
https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

インストールするとリポジトリリストが更新される。

[zaki@cloud-dev ~]$ yum repolist
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.riken.jp
 * epel: ftp.iij.ad.jp
 * extras: ftp.riken.jp
 * updates: ftp.riken.jp
ius                                                                | 1.3 kB  00:00:00
ius/x86_64/primary                                                 | 107 kB  00:00:00
ius                                                                               440/440
リポジトリー ID               リポジトリー名                                        状態
azure-cli                     Azure CLI                                                 80
base/7/x86_64                 CentOS-7 - Base                                       10,070
docker-ce-stable/x86_64       Docker CE Stable - x86_64                                 79
epel/x86_64                   Extra Packages for Enterprise Linux 7 - x86_64        13,445
extras/7/x86_64               CentOS-7 - Extras                                        413
ius/x86_64                    IUS for Enterprise Linux 7 - x86_64                      440
kubernetes                    Kubernetes                                               561
updates/7/x86_64              CentOS-7 - Updates                                     1,127
repolist: 26,215
[zaki@cloud-dev ~]$

gitをsearchしてみる

$ yum search git

[...]

git.x86_64 : Fast Version Control System
git222.x86_64 : Fast Version Control System
git224.x86_64 : Fast Version Control System

なるほど、この辺だな。(git.x86_64は既存のもの)

$ yum info git224
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.riken.jp
 * epel: ftp.iij.ad.jp
 * extras: ftp.riken.jp
 * updates: ftp.riken.jp
利用可能なパッケージ
名前                : git224
アーキテクチャー    : x86_64
バージョン          : 2.24.3
リリース            : 1.el7.ius
容量                : 140 k
リポジトリー        : ius/x86_64
要約                : Fast Version Control System
URL                 : https://git-scm.com/
ライセンス          : GPLv2
説明                : Git is a fast, scalable, distributed revision control system with an
                    : unusually rich command set that provides both high-level operations
                    : and full access to internals.
                    :
                    : The git rpm installs common set of tools which are usually using
                    : with small amount of dependencies. To install all git packages,
                    : including tools for integrating with other SCMs, install the git-all
                    : meta-package.

インストール

before

[zaki@cloud-dev ~]$ git --version
git version 1.8.3.1

installとコンフリクト解消

以下は作業順の記述だけど、結論としては既存gitは削除の必要がある。

$ sudo yum install git224
[zaki@cloud-dev ~]$ sudo yum install git224
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp-srv2.kddilabs.jp
 * epel: ftp.iij.ad.jp
 * extras: ftp-srv2.kddilabs.jp
 * updates: ftp-srv2.kddilabs.jp
ius                                                                | 1.3 kB  00:00:00
ius/x86_64/primary                                                 | 107 kB  00:00:00
ius                                                                               440/440
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ git224.x86_64 0:2.24.3-1.el7.ius を インストール
--> 依存性の処理をしています: perl-Git = 2.24.3-1.el7.ius のパッケージ: git224-2.24.3-1.el7.ius.x86_64
--> 依存性の処理をしています: git-core-doc = 2.24.3-1.el7.ius のパッケージ: git224-2.24.3-1.el7.ius.x86_64
--> 依存性の処理をしています: git-core = 2.24.3-1.el7.ius のパッケージ: git224-2.24.3-1.el7.ius.x86_64
--> 依存性の処理をしています: emacs-filesystem >= 24.3 のパッケージ: git224-2.24.3-1.el7.ius.x86_64
--> 依存性の処理をしています: libsecret-1.so.0()(64bit) のパッケージ: git224-2.24.3-1.el7.ius.x86_64
--> トランザクションの確認を実行しています。
---> パッケージ emacs-filesystem.noarch 1:24.3-23.el7 を インストール
---> パッケージ git224-core.x86_64 0:2.24.3-1.el7.ius を インストール
--> 依存性の処理をしています: libpcre2-8.so.0()(64bit) のパッケージ: git224-core-2.24.3-1.el7.ius.x86_64
---> パッケージ git224-core-doc.noarch 0:2.24.3-1.el7.ius を インストール
---> パッケージ git224-perl-Git.noarch 0:2.24.3-1.el7.ius を インストール
---> パッケージ libsecret.x86_64 0:0.18.6-1.el7 を インストール
--> トランザクションの確認を実行しています。
---> パッケージ pcre2.x86_64 0:10.23-2.el7 を インストール
--> 衝突を処理しています: git224-2.24.3-1.el7.ius.x86_64 は git < 2.24.3-1.el7.ius と衝突
しています
--> 衝突を処理しています: git224-core-2.24.3-1.el7.ius.x86_64 は git-core < 2.24.3-1.el7.ius と衝突しています
--> 衝突を処理しています: git224-perl-Git-2.24.3-1.el7.ius.noarch は perl-Git < 2.24.3-1.el7.ius と衝突しています
--> 依存性解決を終了しました。
エラー: git224-core conflicts with git-1.8.3.1-23.el7_8.x86_64
エラー: git224 conflicts with git-1.8.3.1-23.el7_8.x86_64
エラー: git224-perl-Git conflicts with perl-Git-1.8.3.1-23.el7_8.noarch
 問題を回避するために --skip-broken を用いることができます。
 これらを試行できます: rpm -Va --nofiles --nodigest

既存のGit 1.8とコンフリクトしてるみたい。

[zaki@cloud-dev ~]$ sudo yum remove git
読み込んだプラグイン:fastestmirror
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ git.x86_64 0:1.8.3.1-23.el7_8 を 削除
--> 依存性の処理をしています: git = 1.8.3.1-23.el7_8 のパッケージ: perl-Git-1.8.3.1-23.el7_8.noarch
--> トランザクションの確認を実行しています。
---> パッケージ perl-Git.noarch 0:1.8.3.1-23.el7_8 を 削除
--> 依存性解決を終了しました。

依存性を解決しました

==========================================================================================
 Package            アーキテクチャー バージョン                  リポジトリー        容量
==========================================================================================
削除中:
 git                x86_64           1.8.3.1-23.el7_8            @updates            22 M
依存性関連での削除をします:
 perl-Git           noarch           1.8.3.1-23.el7_8            @updates            57 k

トランザクションの要約
==========================================================================================
削除  1 パッケージ (+1 個の依存関係のパッケージ)

インストール容量: 22 M
上記の処理を行います。よろしいでしょうか? [y/N]

これでコンフリクトしてたものが消えて、インストールできる。

$ sudo yum install git224

after

[zaki@cloud-dev ~]$ git --version
git version 2.24.3

これでGitLensやGit Historyもちゃんと動いた。

f:id:zaki-hmkc:20200912104420p:plain

[コードメモ] Paramikoを使ってPythonでsshする (公開鍵認証)

いきなりサンプルコード。

import paramiko

# 接続
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect("192.168.0.20", username='zaki', key_filename="/home/zaki/.ssh/id_rsa_nopass")

stdin, stdout, stderr = client.exec_command("hostname")
for line in stdout:
    print(line)

client.close()

192.168.0.20にある対向サーバーはCentOS 7の標準のsshdサーバーで、ユーザーzakiで公開鍵認証設定が行われている状態。
秘密鍵ファイルは/home/zaki/.ssh/id_rsa_nopassにあって、パスフレーズは無し。

これで

client.load_system_host_keys()
client.connect()

で接続。

stdin, stdout, stderr = client.exec_command("hostname")

で、sshのコネクション先でコマンド実行。

(paramiko) [zaki@cloud-dev paramiko]$ python sample.py 
manager-dev

ちなみにip aだとコマンドが見つからないというエラーになったため、hostnameのある/usr/binにはパスが通っているが、ipのある/usr/sbinにはパスが設定されていない模様。

client.exec_command("echo $PATH")

試しにこれを実行すると

(paramiko) [zaki@cloud-dev paramiko]$ python sample.py 
/usr/local/bin:/usr/bin

Exception ignored in: <object repr() failed>
Traceback (most recent call last):
  File "/home/zaki/ansible/paramiko/lib/python3.6/site-packages/paramiko/file.py", line 66, in __del__
  File "/home/zaki/ansible/paramiko/lib/python3.6/site-packages/paramiko/channel.py", line 1392, in close
  File "/home/zaki/ansible/paramiko/lib/python3.6/site-packages/paramiko/channel.py", line 991, in shutdown_write
  File "/home/zaki/ansible/paramiko/lib/python3.6/site-packages/paramiko/channel.py", line 963, in shutdown
  File "/home/zaki/ansible/paramiko/lib/python3.6/site-packages/paramiko/channel.py", line 1246, in _send_eof
  File "/home/zaki/ansible/paramiko/lib/python3.6/site-packages/paramiko/message.py", line 232, in add_int
TypeError: 'NoneType' object is not callable

となったため、なぜエラーが発生したかはともかく、PATHは通常のsshを使ったログインとは少し異なるようだ。
インタラクティブじゃないからとかその辺かなぁ。(未確認)

client.exec_command("/usr/sbin/ip a")

フルパスであればもちろん動く。


(paramiko) [zaki@cloud-dev paramiko]$ ssh 192.168.0.20 -i ~/.ssh/id_rsa_nopass 'echo $PATH'
/usr/local/bin:/usr/bin
(paramiko) [zaki@cloud-dev paramiko]$ ssh 192.168.0.20 -i ~/.ssh/id_rsa_nopass -t 'echo $PATH'
/usr/local/bin:/usr/bin
Connection to 192.168.0.20 closed.
(paramiko) [zaki@cloud-dev paramiko]$ ssh 192.168.0.20 -i ~/.ssh/id_rsa_nopass -tt 'echo $PATH'
/usr/local/bin:/usr/bin
Connection to 192.168.0.20 closed.

違うか。別の理由かな


書き忘れてたけど、使用にはparamikoが必要なのでpipでインストールしておく。

$ pip3 install paramiko

無いとエラーになる

(paramiko) [zaki@cloud-dev paramiko]$ python sample.py 
Traceback (most recent call last):
  File "sample.py", line 1, in <module>
    import paramiko
ModuleNotFoundError: No module named 'paramiko'

ちなみに、ssh処理をするコードを書きたくて前情報無しの状態で一番最初に見るのはParamikoのドキュメントよりも、Demoコードが載っているGitHubのReadmeが良いかもしれない。

github.com

docs.paramiko.org

www.paramiko.org

[ESXi / Ansible] ssh接続してvmi-cmdを使ったVM操作が可能かお試し

ESXiのsshを有効にすると、ssh接続できる。

f:id:zaki-hmkc:20200910214002p:plain

Copyright (C) Microsoft Corporation. All rights reserved.

新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6

PS C:\Users\zaki> ssh root@192.168.0.2
The authenticity of host '192.168.0.2 (192.168.0.2)' can't be established.
RSA key fingerprint is SHA256:niylnBGGHVs8r24g52aq1czc6JKg4MDvqpeGjbHikQk.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.2' (RSA) to the list of known hosts.
Password:
The time and date of this login have been sent to the system logs.

WARNING:
   All commands run on the ESXi shell are logged and may be included in
   support bundles. Do not provide passwords directly on the command line.
   Most tools can prompt for secrets or accept them from standard input.

VMware offers supported, powerful system administration tools.  Please
see www.vmware.com/go/sysadmintools for details.

The ESXi Shell can be disabled by an administrative user. See the
vSphere Security documentation for more information.
[root@localhost:~] uname -a
VMkernel localhost.naru.jp-z.jp 6.5.0 #1 SMP Release build-8294253 Apr 17 2018 19:05:39 x86_64 x86_64 x86_64 ESXi
[root@localhost:~] ls
altbootbank      dev              local.tgz        proc             store            usr              vmupgrade
bin              etc              locker           productLocker    tardisks         var
bootbank         lib              mbr              sbin             tardisks.noauto  vmfs
bootpart.gz      lib64            opt              scratch          tmp              vmimages
[root@localhost:~]

この通り、ESXiのweb画面でログインするときのアカウントでsshできる。

[root@localhost:~] which python
/bin/python
[root@localhost:~] python --version
Python 3.5.3

Pythonインタプリタも入っている。

よし、Ansibleで何かできるかな。

ssh接続してlsする

inventory

becomeでrootになるのではなく、初めからrootでssh接続したいので、ansible_userを指定する。
パスワードはtext/plainでの記述に気にしないならansible_passwordで書いてもよい。
またはansible-vaultを使った暗号化という手もある。

今回は手っ取り早く、inventoryには記載なし、実行時に-kインタラクティブに入力とする。

[esxi]
host ansible_host=192.168.0.2 ansible_user=root

playbook

ESXiホスト上でls -lして結果をdebugで表示してみる。

- hosts: esxi
  gather_facts: false
  tasks:
  - name: exec command
    command: /bin/ls -l
    register: result

  - name: result
    debug:
      msg: "{{result.stdout}}"

実行結果

(2.9) [zaki@cloud-dev get-vmlist]$ ansible-playbook -i inventory.ini playbook.yml -k
SSH password: 

PLAY [esxi] *****************************************************************************************************

TASK [exec command] *********************************************************************************************
[WARNING]: No python interpreters found for host host (tried ['/usr/bin/python', 'python3.7', 'python3.6',
'python3.5', 'python2.7', 'python2.6', '/usr/libexec/platform-python', '/usr/bin/python3', 'python'])
changed: [host]

TASK [result] ***************************************************************************************************
ok: [host] => 
  msg: |-
    total 725
    lrwxrwxrwx    1 root     root            49 Aug  8 09:19 altbootbank -> /vmfs/volumes/5d0f317f-6bd852f3-5e45-fcdbf5dfbc4f
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 bin
    lrwxrwxrwx    1 root     root            49 Aug  8 09:19 bootbank -> /vmfs/volumes/a65abe71-c4f310cb-9086-addf2d180ac6
    -r--r--r--    1 root     root        505734 Apr 18  2018 bootpart.gz
    drwxr-xr-x   13 root     root           512 Sep 10 10:54 dev
    drwxr-xr-x    1 root     root           512 Aug  8 09:27 etc
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 lib
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 lib64
    -r-x------    1 root     root         15842 Aug  8 09:06 local.tgz
    lrwxrwxrwx    1 root     root             6 Aug  8 09:19 locker -> /store
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 mbr
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 opt
    drwxr-xr-x    1 root     root        131072 Sep 10 10:54 proc
    lrwxrwxrwx    1 root     root            23 Aug  8 09:19 productLocker -> /locker/packages/6.5.0/
    lrwxrwxrwx    1 root     root             4 Apr 18  2018 sbin -> /bin
    lrwxrwxrwx    1 root     root            49 Aug  8 09:19 scratch -> /vmfs/volumes/5d8faab9-e7f59692-e859-1c697a00ef17
    lrwxrwxrwx    1 root     root            49 Aug  8 09:19 store -> /vmfs/volumes/5d8faab2-9eb79d0c-7790-1c697a00ef17
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 tardisks
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 tardisks.noauto
    drwxrwxrwt    1 root     root           512 Sep 10 10:54 tmp
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 usr
    drwxr-xr-x    1 root     root           512 Aug  8 09:19 var
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 vmfs
    drwxr-xr-x    1 root     root           512 Aug  8 09:18 vmimages
    lrwxrwxrwx    1 root     root            18 Apr 18  2018 vmupgrade -> /locker/vmupgrade/

PLAY RECAP ******************************************************************************************************
host                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

(2.9) [zaki@cloud-dev get-vmlist]$ 

VM一覧を取得してファイルに出力

上記のssh接続してlsをベースに実行するコマンドを変更。
実行するのはvim-cmd vmsvc/getallvms

普通に実行するとこんな感じ。

[root@localhost:~] vim-cmd vmsvc/getallvms
Vmid              Name                                                 File                                          Guest OS       Version   Annotation
1      example                       [datastore1] example/example.vmx                                            centos7_64Guest    vmx-13
103    k8s-master03.esxi.jp-z.jp     [WDS100T2B0A] k8s-master03.esxi.jp-z.jp/k8s-master03.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
105    k8s-worker04.esxi.jp-z.jp     [WDS100T2B0A] k8s-worker04.esxi.jp-z.jp/k8s-worker04.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
106    cloud-dev                     [WDS100T2B0A] cloud-dev_1/cloud-dev_1.vmx                                   centos7_64Guest    vmx-13
107    desktop                       [WDS100T2B0A] desktop/desktop.vmx                                           ubuntu64Guest      vmx-13
108    desktop2                      [WDS100T2B0A] desktop2/desktop2.vmx                                         ubuntu64Guest      vmx-13
11     test.vm                       [WDS100T2B0A] test.vm/test.vm.vmx                                           centos7_64Guest    vmx-13    test vm
111    restricted-rhel7              [WDS100T2B0A] restricted-rhel7/restricted-rhel7.vmx                         rhel7_64Guest      vmx-13
13     debian-desktop                [WDS100T2B0A] debian-desktop/debian-desktop.vmx                             debian10_64Guest   vmx-13
23     windows                       [WDS100T2B0A] windows8x64/windows8x64.vmx                                   windows8_64Guest   vmx-13
25     okd-manager.esxi.jp-z.jp      [WDS100T2B0A] okd-manager.esxi.jp-z.jp/okd-manager.esxi.jp-z.jp.vmx         centos7_64Guest    vmx-13
26     okd-master.esxi.jp-z.jp       [WDS100T2B0A] okd-master.esxi.jp-z.jp/okd-master.esxi.jp-z.jp.vmx           centos7_64Guest    vmx-13
27     okd-node1.esxi.jp-z.jp        [WDS100T2B0A] okd-node1.esxi.jp-z.jp/okd-node1.esxi.jp-z.jp.vmx             centos7_64Guest    vmx-13
28     okd-node2.esxi.jp-z.jp        [WDS100T2B0A] okd-node2.esxi.jp-z.jp/okd-node2.esxi.jp-z.jp.vmx             centos7_64Guest    vmx-13
33     minikube.jp-z.jp              [WDS100T2B0A] minikube.jp-z.jp/minikube.jp-z.jp.vmx                         centos7_64Guest    vmx-13
45     manager-dev                   [WDS100T2B0A] manager-dev/manager-dev.vmx                                   centos7_64Guest    vmx-13
51     desktop-ubuntu                [WDS100T2B0A] desktop-ubuntu/desktop-ubuntu.vmx                             ubuntu64Guest      vmx-13
53     desktop-centos                [WDS100T2B0A] desktop-centos/desktop-centos.vmx                             centos7_64Guest    vmx-13
54     registry                      [WDS100T2B0A] registry/registry.vmx                                         centos7_64Guest    vmx-13
62     okd4-manager.esxi.jp-z.jp     [WDS100T2B0A] okd4-manager.esxi.jp-z.jp/okd4-manager.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
69     okd4-bootstrap.esxi.jp-z.jp   [WDS100T2B0A] okd4-bootstrap.esxi.jp-z.jp/okd4-bootstrap.esxi.jp-z.jp.vmx   coreos64Guest      vmx-13
7      manager.local.jp-z.jp         [WDS100T2B0A] manager.local.jp-z.jp/manager.local.jp-z.jp.vmx               centos7_64Guest    vmx-13
70     okd4-master0.esxi.jp-z.jp     [WDS100T2B0A] okd4-master0.esxi.jp-z.jp/okd4-master0.esxi.jp-z.jp.vmx       coreos64Guest      vmx-13
71     okd4-master1.esxi.jp-z.jp     [WDS100T2B0A] okd4-master1.esxi.jp-z.jp/okd4-master1.esxi.jp-z.jp.vmx       coreos64Guest      vmx-13
72     okd4-master2.esxi.jp-z.jp     [WDS100T2B0A] okd4-master2.esxi.jp-z.jp/okd4-master2.esxi.jp-z.jp.vmx       coreos64Guest      vmx-13
73     okd4-worker0.esxi.jp-z.jp     [WDS100T2B0A] okd4-worker0.esxi.jp-z.jp/okd4-worker0.esxi.jp-z.jp.vmx       coreos64Guest      vmx-13
74     okd4-worker1.esxi.jp-z.jp     [WDS100T2B0A] okd4-worker1.esxi.jp-z.jp/okd4-worker1.esxi.jp-z.jp.vmx       coreos64Guest      vmx-13
75     pxe-sample                    [WDS100T2B0A] pxe-sample/pxe-sample.vmx                                     centos7_64Guest    vmx-13
77     win10-offline                 [WDS100T2B0A] win10-offline/win10-offline.vmx                               windows9_64Guest   vmx-13
78     restricted-centos             [WDS100T2B0A] restricted-centos/restricted-centos.vmx                       centos7_64Guest    vmx-13
91     k8s-master01.esxi.jp-z.jp     [WDS100T2B0A] k8s-master01.esxi.jp-z.jp/k8s-master01.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
92     k8s-worker01.esxi.jp-z.jp     [WDS100T2B0A] k8s-worker01.esxi.jp-z.jp/k8s-worker01.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
95     esxi-host                     [WDS100T2B0A] esxi-host/esxi-host.vmx                                       vmkernel65Guest    vmx-13
96     k8s-master02.esxi.jp-z.jp     [WDS100T2B0A] k8s-master02.esxi.jp-z.jp/k8s-master02.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
97     k8s-worker02.esxi.jp-z.jp     [WDS100T2B0A] k8s-worker02.esxi.jp-z.jp/k8s-worker02.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
98     k8s-worker03.esxi.jp-z.jp     [WDS100T2B0A] k8s-worker03.esxi.jp-z.jp/k8s-worker03.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13
99     k8s-manager.esxi.jp-z.jp      [WDS100T2B0A] k8s-manager.esxi.jp-z.jp/k8s-manager.esxi.jp-z.jp.vmx         centos7_64Guest    vmx-13

j2テンプレート

template.j2で作成。
内容はこれだけ。

{{ result.stdout }}

playbook

- hosts: esxi
  gather_facts: false
  tasks:
  - name: exec command
    command: vim-cmd vmsvc/getallvms
    register: result

  - name: create vm list file
    template:
      src: template.j2
      dest: getallvms.log
    delegate_to: localhost

ポイントはdelegate_tolocalhostを指定していること。
これが無いと、ESXiホスト上にtemplateを使ってファイル生成してしまう。

実行結果

(2.9) [zaki@cloud-dev get-vmlist]$ ansible-playbook -i inventory.ini playbook.yml -k
SSH password: 

PLAY [esxi] *****************************************************************************************************

TASK [exec command] *********************************************************************************************
[WARNING]: No python interpreters found for host host (tried ['/usr/bin/python', 'python3.7', 'python3.6',
'python3.5', 'python2.7', 'python2.6', '/usr/libexec/platform-python', '/usr/bin/python3', 'python'])
changed: [host]

TASK [create vm list file] **************************************************************************************
changed: [host]

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

(2.9) [zaki@cloud-dev get-vmlist]$ 
(2.9) [zaki@cloud-dev get-vmlist]$ head -3 getallvms.log 
Vmid              Name                                                 File                                          Guest OS       Version   Annotation
1      example                       [datastore1] example/example.vmx                                            centos7_64Guest    vmx-13              
103    k8s-master03.esxi.jp-z.jp     [WDS100T2B0A] k8s-master03.esxi.jp-z.jp/k8s-master03.esxi.jp-z.jp.vmx       centos7_64Guest    vmx-13              
(2.9) [zaki@cloud-dev get-vmlist]$ 

delegate_toを使わないのであれば、command実行はESXi、template実行はローカルと、タスクを分けるのが一番手っ取り早い。 ただしその場合はregisterの値はESXiのホストグループ側にセットされるのでホスト変数を参照する必要がある。

具体的にはテンプレートでは{{ hostvars[groups.esxi[0]].result.stdout }}みたいな感じで取り出せる。

zaki-hmkc.hatenablog.com

また、localhostをターゲットにする場合は、CentOS7でpip3の場合だとPythonインタプリタの指定とinventoryでlocalhost指定が必要かもしれないので注意。

write系処理

無償ライセンスのESXiだとwrite系APIが使えないため、VMのon/offとかもできないんだけど、このvim-cmdであれば可能。

  • poweron

    [root@localhost:~] vim-cmd vmsvc/power.on 78 Powering on VM:

  • poweroff

    [root@localhost:~] vim-cmd vmsvc/power.off 78 Powering off VM:

  • shutdown (要VMware Tools)

    [root@localhost:~] vim-cmd vmsvc/power.shutdown 45

みたいな感じ。(引数はリストで得られるVmid)

ただ、処理に必要なこのVmidを取り出したりするために、それなりのテキスト処理をグリグリやる必要があるので「AnsibleのターゲットホストにESXiを指定してsshで接続してshell/commandでがんばる」のはかなりの力技になりそう。

力技なのはかわりないけれど、playbookがスッキリするという点ではモジュール作成の題材にすると良さげ。

ちなみにやろうとしてたのは、ESXiのアップデートをAnsibleで自動化できないかなーというもの。
コマンド実行するくらいであればこの延長でできそうだけど、「onの状態のVMをすべてシャットダウン」とかはグリグリしないとだめかも。


エラーと対処

fatal: [host]: FAILED! => changed=false 
  ansible_facts:
    discovered_interpreter_python: /usr/bin/python
  cmd: /bin/ls -l
  msg: '[Errno 38] Function not implemented'
  rc: 38
$ ansible --version
ansible 2.9.10
  config file = /home/zaki/src/ansible-vmware/ssh/get-vmlist/ansible.cfg
  configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/zaki/.local/lib/python3.6/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.6.8 (default, Apr  2 2020, 13:34:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

以上の環境で発生。
検索してみると、以下のissueを発見

github.com

どうやらバージョンの組み合わせ固有の現象っぽい。。 現時点の2.9系最新であるAnsible 2.9.13に更新すると解消。

ESXiシェルのログ

[監視]->[ログ]->[/var/log/shell.log]で確認できる。

f:id:zaki-hmkc:20200910214153p:plain


参考情報

kb.vmware.com

qiita.com

キレイにまとまったリファレンス情報が見当たらない。。

[Docker]コンテナ実行時にlog-optsでログサイズ上限とローテート数を設定してホストのストレージが溢れないようにする

コンテナのお作法として、アプリのログはstdoutへ出力することで、Dockerのロギング機能に任せることができる。
ただし、Dockerのデフォルトだとサイズ制限は無いので、上限設定を行っていないとホストのストレージを使い切ってしまうので注意。

逆に言うと、アプリのログはDockerにまかせることで、サイズ上限やローテートもやってくれるので、ログローテートの仕組みを別途用意する必要はない。

※ CPUとメモリについてはこちら。

zaki-hmkc.hatenablog.com

確認用Dockerイメージ作成

#!/bin/bash

echo "container started..."

while true;
do
    echo "$(date +'%Y-%m-%d %H-%M-%S'): $(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 64)"
    usleep 100000
done
FROM centos:7

RUN yum install -y initscripts && \
    yum clean all
COPY createlog.sh /createlog.sh

CMD ["/createlog.sh"]
$ sudo docker build -t log-sample .
$ sudo docker images log-sample
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
log-sample          latest              b4ec88d926dc        31 seconds ago      203MB

(補足) スクリプト解説

cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 64は、ランダムな[a-zA-Z0-9]の文字を64バイトだけ出力。
あとusleepはmicrosecondsでsleepするコマンド。centos:7イメージにはデフォルトで入ってなかったのでyumで追加している。
sleepを入れているのは負荷があがりすぎないようにするためと、停止のシグナルをキャッチしやすくするため。

docker run オプション

ログサイズ制限ありで実行

設定するのは以下。

      --log-opt list                   Log driver options

optionsの内訳は--helpだと確認できないのでドキュメント確認。

docs.docker.com

実はここを見てもよくわからない。
というのも--log-optオプションは--log-driverに指定するログドライバによって設定できるオプションが変わるため。
今回はデフォルトのjson-fileについて。
json-file--log-driverはこちら。

docs.docker.com

ログファイルのサイズを制限するのはこれ。

max-size

今回は制限がかかることを見るだけなので、100KBとする。

$ sudo docker run -d --rm --log-opt max-size=100k log-sample
a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a

ログファイルの出力先を確認

$ sudo docker inspect a7f | grep LogPath
        "LogPath": "/var/lib/docker/containers/a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a/a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a-json.log",

ログファイルのサイズを確認する

$ ls -lh /var/lib/docker/containers/a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a/a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a-json.log
[zaki@example ~]$ sudo ls -lh /var/lib/docker/containers/a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a/
合計 152K
-rw-r-----. 1 root root  98K  9月  9 20:26 a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a-json.log
drwx------. 2 root root    6  9月  9 20:24 checkpoints
-rw-------. 1 root root 2.9K  9月  9 20:24 config.v2.json
-rw-r--r--. 1 root root 1.5K  9月  9 20:24 hostconfig.json
-rw-r--r--. 1 root root   13  9月  9 20:24 hostname
-rw-r--r--. 1 root root  174  9月  9 20:24 hosts
drwx------. 2 root root    6  9月  9 20:24 mounts
-rw-r--r--. 1 root root   66  9月  9 20:24 resolv.conf
-rw-r--r--. 1 root root   71  9月  9 20:24 resolv.conf.hash
[zaki@example ~]$ sudo ls -lh /var/lib/docker/containers/a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a/
合計 28K
-rw-r-----. 1 root root  780  9月  9 20:26 a7fe3ed543c26bac2f50a93f4ef5a068fffe26ec0523872d23552c64b0b4705a-json.log
drwx------. 2 root root    6  9月  9 20:24 checkpoints
-rw-------. 1 root root 2.9K  9月  9 20:24 config.v2.json
-rw-r--r--. 1 root root 1.5K  9月  9 20:24 hostconfig.json
-rw-r--r--. 1 root root   13  9月  9 20:24 hostname
-rw-r--r--. 1 root root  174  9月  9 20:24 hosts
drwx------. 2 root root    6  9月  9 20:24 mounts
-rw-r--r--. 1 root root   66  9月  9 20:24 resolv.conf
-rw-r--r--. 1 root root   71  9月  9 20:24 resolv.conf.hash
[zaki@example ~]$

この通り、100KBに達するとログがローテートされる。
ただ、見ればわかる通り、ローテートというよりはクリアされてしまうので、制限サイズの境界のタイミングでログがゼロになる瞬間ができてします。

世代数の設定

もう一つ設定すると良いオプションがローテートのファイル数。

max-file
$ sudo docker run -d --rm --log-opt max-size=100k --log-opt max-file=3 log-sample
f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561
$ sudo docker inspect f4ce | grep LogPath
        "LogPath": "/var/lib/docker/containers/f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561/f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561-json.log",

このままログの出力を見ていると

[zaki@example ~]$ sudo ls -lh /var/lib/docker/containers/f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561
合計 72K
drwx------. 2 root root    6  9月  9 20:36 checkpoints
-rw-------. 1 root root 2.9K  9月  9 20:36 config.v2.json
-rw-r-----. 1 root root  45K  9月  9 20:37 f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561-json.log
-rw-r--r--. 1 root root 1.5K  9月  9 20:36 hostconfig.json
-rw-r--r--. 1 root root   13  9月  9 20:36 hostname
-rw-r--r--. 1 root root  174  9月  9 20:36 hosts
drwx------. 2 root root    6  9月  9 20:36 mounts
-rw-r--r--. 1 root root   66  9月  9 20:36 resolv.conf
-rw-r--r--. 1 root root   71  9月  9 20:36 resolv.conf.hash

これが

[zaki@example ~]$ sudo ls -lh /var/lib/docker/containers/f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561
合計 152K
drwx------. 2 root root    6  9月  9 20:36 checkpoints
-rw-------. 1 root root 2.9K  9月  9 20:36 config.v2.json
-rw-r-----. 1 root root  97K  9月  9 20:37 f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561-json.log
-rw-r--r--. 1 root root 1.5K  9月  9 20:36 hostconfig.json
-rw-r--r--. 1 root root   13  9月  9 20:36 hostname
-rw-r--r--. 1 root root  174  9月  9 20:36 hosts
drwx------. 2 root root    6  9月  9 20:36 mounts
-rw-r--r--. 1 root root   66  9月  9 20:36 resolv.conf
-rw-r--r--. 1 root root   71  9月  9 20:36 resolv.conf.hash

こうなって

[zaki@example ~]$ sudo ls -lh /var/lib/docker/containers/f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561
合計 128K
drwx------. 2 root root    6  9月  9 20:36 checkpoints
-rw-------. 1 root root 2.9K  9月  9 20:36 config.v2.json
-rw-r-----. 1 root root  467  9月  9 20:37 f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561-json.log
-rw-r-----. 1 root root  98K  9月  9 20:37 f4ce850b1d1569c89f468d969fa5686f57891256807d47a13c1b3a04b0047561-json.log.1
-rw-r--r--. 1 root root 1.5K  9月  9 20:36 hostconfig.json
-rw-r--r--. 1 root root   13  9月  9 20:36 hostname
-rw-r--r--. 1 root root  174  9月  9 20:36 hosts
drwx------. 2 root root    6  9月  9 20:36 mounts
-rw-r--r--. 1 root root   66  9月  9 20:36 resolv.conf
-rw-r--r--. 1 root root   71  9月  9 20:36 resolv.conf.hash
[zaki@example ~]$

こうじゃ

設定なし

$ sudo docker run -d --rm log-sample
d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4
$ sudo docker inspect d76 | grep LogPath
        "LogPath": "/var/lib/docker/containers/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4-json.log",
$ sudo ls -lh /var/lib/docker/containers/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4/d76da2cccf741f100e10898ae4c2644a98e3a3584807
0bc6e652a2cb793fbba4-json.log
-rw-r-----. 1 root root 33K  9月  9 20:45 /var/lib/docker/containers/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4-json.log
$ sudo ls -lh /var/lib/docker/containers/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4-json.log
-rw-r-----. 1 root root 124K  9月  9 20:46 /var/lib/docker/containers/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4/d76da2cccf741f100e10898ae4c2644a98e3a35848070bc6e652a2cb793fbba4-json.log

この通り100KB超えても普通に書き込みされる。

ちなみにログはこんな感じ。

$ sudo docker logs d76 | head -5
container started...
2020-09-09 11-44-50: NqQqgo00wBOqbFHzes2cQ6mOMet03upgyVh3C7QyuT8Ttr79ZcQF82jUhjfeb3sL
2020-09-09 11-44-50: vugDHpHItrnQZNhzoJCw925ClX486NrFoBgs4OhvqHYmgUbHXrN790dhuJtks7Nq
2020-09-09 11-44-50: oQZfA9oPlSO7RUl6yboTs75qpa6WIkjwD0EWxHfqB8ipftuM4EfoMeDj6uaKxTpC
2020-09-09 11-44-50: U62VsIkIzqau1eEinGIkpGEK1ckoesuVxTMDy9ZMZoWKXoAaektSt0LCyxh1V5o7

システムワイドに設定

オプション指定を忘れてると青天井に実行されても困るという場合は、デフォルトの設定にもできる。

docs.docker.com

前述の例のように、100KBで3世代であれば以下の通り。

$ cat /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100k",
    "max-file": "3"
  }
}

設定変更したらサービスを再起動

$ sudo systemctl restart docker
$ sudo docker run -d --rm log-sample
69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5
$ sudo docker inspect 69d | grep LogPath
        "LogPath": "/var/lib/docker/containers/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5-json.log",
$ sudo ls -lh /var/lib/docker/containers/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5-json.log
-rw-r-----. 1 root root 39K  9月  9 20:54 /var/lib/docker/containers/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5-json.log

ファイルサイズをチェックしてると、この通り。

[zaki@example ~]$ sudo ls -lh /var/lib/docker/containers/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5
合計 152K
-rw-r-----. 1 root root  98K  9月  9 20:55 69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5-json.log
drwx------. 2 root root    6  9月  9 20:53 checkpoints
-rw-------. 1 root root 2.9K  9月  9 20:53 config.v2.json
-rw-r--r--. 1 root root 1.5K  9月  9 20:53 hostconfig.json
-rw-r--r--. 1 root root   13  9月  9 20:53 hostname
-rw-r--r--. 1 root root  174  9月  9 20:53 hosts
drwx------. 2 root root    6  9月  9 20:53 mounts
-rw-r--r--. 1 root root   66  9月  9 20:53 resolv.conf
-rw-r--r--. 1 root root   71  9月  9 20:53 resolv.conf.hash
[zaki@example ~]$ sudo ls -lh /var/lib/docker/containers/69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5
合計 128K
-rw-r-----. 1 root root  780  9月  9 20:55 69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5-json.log
-rw-r-----. 1 root root  98K  9月  9 20:55 69d476241d84e90522536bf8261c5fb2cae550a160258341999c5d3c812aaaf5-json.log.1
drwx------. 2 root root    6  9月  9 20:53 checkpoints
-rw-------. 1 root root 2.9K  9月  9 20:53 config.v2.json
-rw-r--r--. 1 root root 1.5K  9月  9 20:53 hostconfig.json
-rw-r--r--. 1 root root   13  9月  9 20:53 hostname
-rw-r--r--. 1 root root  174  9月  9 20:53 hosts
drwx------. 2 root root    6  9月  9 20:53 mounts
-rw-r--r--. 1 root root   66  9月  9 20:53 resolv.conf
-rw-r--r--. 1 root root   71  9月  9 20:53 resolv.conf.hash

この制限を入れていないと、ホストOSのストレージをすべて使い切るまでファイル書き込みしてしまうので注意。(訳:やらかした)
どの設定も、目的はホストOSのリソースを喰いつくさないように安定性を高める。


追記: inspectで確認

ログサイズ制限を行ったコンテナをdocker inspectで確認すると以下の通り。

        "HostConfig": {
            [...]
            "LogConfig": {
                "Type": "json-file",
                "Config": {
                    "max-size": "100k"
                }
            },

[Docker] コンテナで動かすプロセスのCPU使用率を--cpusで、メモリ使用量を--memoryで制限する

あくまで一例です。
開発環境とかで一時的に使うのでなく、サービスとして永続的に使う場合は、ホストのリソースを食い尽くさないように制限をかけると良い。

※ ログサイズについてはこちら

zaki-hmkc.hatenablog.com

CPU

制限無し

[zaki@cloud-dev ~]$ docker run --rm -it centos:7 bash
[root@fb3e8ba23a4d /]# 
top - 20:00:32 up 6 days, 11:09,  4 users,  load average: 0.02, 0.05, 0.05
Tasks: 334 total,   1 running, 333 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  7990068 total,   334524 free,  4077584 used,  3577960 buff/cache
KiB Swap:  3670012 total,  3663100 free,     6912 used.  3565080 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 32689 zaki      20   0  162256   2480   1576 R   0.7  0.0   0:00.08 top
     1 root      20   0  193880   6468   3812 S   0.0  0.1   0:05.94 systemd
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.05 kthreadd
     4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
     6 root      20   0       0      0      0 S   0.0  0.0   0:10.00 ksoftirqd/0

こんな感じ。

ここで負荷試験ツールである(負荷試験ツールでは無い)yesを実行する。(/dev/nullに捨てるのを忘れずに)

[root@fb3e8ba23a4d /]# yes > /dev/null

topはこんな感じ。(CPUは1押下してコア毎の表示)

top - 20:08:41 up 6 days, 11:17,  4 users,  load average: 0.08, 0.09, 0.07
Tasks: 336 total,   2 running, 334 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.3 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 98.7 us,  1.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  7990068 total,   232872 free,  4103872 used,  3653324 buff/cache
KiB Swap:  3670012 total,  3663100 free,     6912 used.  3538792 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 33045 root      20   0    4368    356    280 R 100.0  0.0   0:06.16 yes
 32689 zaki      20   0  162256   2480   1576 R   0.3  0.0   0:01.10 top
     1 root      20   0  193880   6468   3812 S   0.0  0.1   0:05.98 systemd
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.05 kthreadd
     4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
     6 root      20   0       0      0      0 S   0.0  0.0   0:10.01 ksoftirqd/0
     7 root      rt   0       0      0      0 S   0.0  0.0   0:00.49 migration/0
     8 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcu_bh
     9 root      20   0       0      0      0 S   0.0  0.0   1:01.89 rcu_sched

この通り、100%使い切っている。

制限あり

docker runのオプションの--cpuを使用する。

      --cpus decimal                   Number of CPUs

例として30%制限で実行してみる。
追加するオプションは--cpus 0.3

docker run --cpus 0.3 --rm -it centos:7 bash

[zaki@cloud-dev ~]$ docker run --cpus 0.3 --rm -it centos:7 bash
[root@9d2afc703344 /]#

これで同じように負荷試験ツール(負荷試験ツールではない)を実行する。

[root@9d2afc703344 /]# yes > /dev/null
top - 20:12:57 up 6 days, 11:21,  4 users,  load average: 0.01, 0.07, 0.07
Tasks: 334 total,   2 running, 332 sleeping,   0 stopped,   0 zombie
%Cpu0  : 29.8 us,  0.7 sy,  0.0 ni, 69.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  7990068 total,   233236 free,  4103396 used,  3653436 buff/cache
KiB Swap:  3670012 total,  3663100 free,     6912 used.  3539264 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 33182 root      20   0    4368    352    280 R  29.9  0.0   0:03.66 yes
  1054 root      20   0  902308  46228  13440 S   0.3  0.6   8:48.25 containerd
 22511 zaki      20   0 1248016  72048  16856 S   0.3  0.9   2:45.80 node
 33054 zaki      20   0  162256   2476   1576 R   0.3  0.0   0:00.20 top
     1 root      20   0  193880   6500   3844 S   0.0  0.1   0:05.99 systemd
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.05 kthreadd
     4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H

この通り、CPU使用率30%に制限できました。

メモリ

制限無し

[root@4f061ab0d609 /]# /dev/null < $(yes)
top - 20:32:15 up 6 days, 11:41,  5 users,  load average: 0.54, 0.20, 0.10
Tasks: 341 total,   3 running, 338 sleeping,   0 stopped,   0 zombie
%Cpu(s): 27.1 us, 14.5 sy,  0.0 ni, 58.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  7990068 total,   135848 free,  6148588 used,  1705632 buff/cache
KiB Swap:  3670012 total,  3650556 free,    19456 used.  1494248 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 33771 root      20   0 2091740   2.0g    472 R  97.0 26.0   0:17.83 bash
 33772 root      20   0    4368    352    280 R  69.1  0.0   0:12.94 yes
    45 root      20   0       0      0      0 S   0.7  0.0   0:03.09 kswapd0
 33416 zaki      20   0  162256   2472   1576 R   0.3  0.0   0:00.55 top
     1 root      20   0  193880   6168   3512 S   0.0  0.1   0:06.07 systemd
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.05 kthreadd
     4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
root      33715  0.0  0.0 107560  3240 ?        Sl   20:31   0:00  \_ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/4f061ab0d60936997b8f90fd2155e3ca4843036f557ef6efb60967e2350a8268 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc -systemd-cgroup
root      33733  0.1  0.0  11828  1904 pts/0    Ss   20:31   0:00      \_ bash
root      33771 98.1 17.4 1403428 1392432 pts/0 R+   20:31   0:11          \_ bash
root      33772 71.2  0.0   4368   352 pts/0    R    20:31   0:08              \_ yes
[root@4f061ab0d609 /]# /dev/null < $(yes)
bash: xrealloc: cannot allocate 18446744071562067968 bytes (331776 bytes allocated)
[root@4f061ab0d609 /]#

2GBの時点でメモリアロケートに失敗して停止した。(コンテナではなくyesを実行しているプロセスが)
この制限は未調査。

ulimitで見える範囲ではとくに制限はないんだけど。

[zaki@cloud-dev ~]$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31118
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 4096
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

追記: 2GB仕様について

2GB制限はおそらく確認に使用した/dev/null < $(yes)で使用されるbashの制限か仕様。
Cで「mallo(3)をforループでぶん回す」プログラムを書いてコンテナで動かすと、特に制限なく動作した。

制限あり

--memoryで制限を設定できる。

  -m, --memory bytes                   Memory limit

例として512MBで制限を掛けてみる。

[zaki@cloud-dev ~]$ docker run -m 512m --rm -it centos:7 bash
[root@e9787badb7c0 /]#
[zaki@cloud-dev ~]$ top
top - 20:38:04 up 6 days, 11:46,  5 users,  load average: 0.61, 0.28, 0.15
Tasks: 339 total,   2 running, 337 sleeping,   0 stopped,   0 zombie
%Cpu(s): 25.2 us, 15.6 sy,  0.0 ni, 58.4 id,  0.0 wa,  0.0 hi,  0.8 si,  0.0 st
KiB Mem :  7990068 total,  1693808 free,  4591392 used,  1704868 buff/cache
KiB Swap:  3670012 total,  3197180 free,   472832 used.  3050796 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 34133 root      20   0  985940 521512    472 R  98.3  6.5   0:08.44 bash
 34134 root      20   0    4368    280    280 S  64.8  0.0   0:05.75 yes
 34042 zaki      20   0  162256   2484   1576 R   0.3  0.0   0:00.09 top
 57182 root      20   0       0      0      0 S   0.3  0.0   0:39.54 kworker/0:1
     1 root      20   0  193880   6172   3516 S   0.0  0.1   0:06.11 systemd

この辺までは負荷がかかるが、RESの数値の通り512MBあたりで頭打ち。
そのまま停止する。

[root@18fd18524341 /]# /dev/null < $(yes)
Killed

お、出力が違う。。

出力メッセージの違いはbash周りの内部処理に依存していて詳細は未確認だが、設定している512MB程度以上のリソースを使用することはできないようになる。
(制限を超えたメモリをallocateしようとしてエラーになったらクラッシュするようになっているのだろう)

その他のオプション

--oom-kill-disableでOOMを無効にしたり、--memory-swapでswap込みのメモリ量を設定もできる模様。
詳しくはドキュメント参照。

参考

docs.docker.com

knowledge.sakura.ad.jp

環境

[zaki@cloud-dev ~]$ docker version
Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:46:54 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:45:28 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
[zaki@cloud-dev ~]$ uname -r
3.10.0-1127.18.2.el7.x86_64
[zaki@cloud-dev ~]$ cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)

制限という意味では、あとログファイルサイズも制限しておかないと、あふれる。(訳:あふれた)


追記: docker statsを使ったコンテナ毎のリソース使用状況

コンテナ毎のリソース使用状況はdocker statsでも見れる。(知らなかった!)

f:id:zaki-hmkc:20200908215651p:plain

topより断然見やすいです(笑)


追記: inspectで確認

docker inspectで制限をかけているコンテナを確認すると、HostConfig以下のMemoryNanoCpusに指定した数値が設定される。
docker run --cpus 0.3 -m 512m --rm -it centos:7 bashした場合は以下の通り。

        "HostConfig": {
            [...]
            "Memory": 536870912,
            "NanoCpus": 300000000,

制限を行っていない場合は、どちらも0になる。

[Ansible] creates/removesを指定してcommand使用時のファイルの有無事前チェックを行う

commandshellモジュール使用時の冪等性の処理に「事前チェックtaskを実行、結果をregisterで保持、その内容を使ってwhenでガード」ってよくするけど、ファイルの有無程度であれば標準機能でカバーできる。
(commandの結果ファイルを生成するような処理の場合、そのファイルが作成済みであればスルーする、など)

docs.ansible.com

以下すべてcommandの例だけど、shellも同じ動作。
確認した環境は以下の通り。

[zaki@cloud-dev ansible-work]$ cat /etc/redhat-release 
CentOS Linux release 7.8.2003 (Core)
[zaki@cloud-dev ansible-work]$ ansible-playbook --version
ansible-playbook 2.9.10
  config file = None
  configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/zaki/.local/lib/python3.6/site-packages/ansible
  executable location = /usr/local/bin/ansible-playbook
  python version = 3.6.8 (default, Apr  2 2020, 13:34:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

書式

command:の行に実行するコマンドを書かずに、cmd:をパラメタとして渡すように書く。そこにcreatesremovesも追加する。

  - name: mv file
    command:
      cmd: mv /tmp/zzz-src /tmp/zzz-dest
      removes: /tmp/zzz-src

以下のように書くとエラーになる。

  - name: mv file
    command: mv /tmp/zzz-src /tmp/zzz-dest
      removes: /tmp/zzz-src

というかそもそもこれはYAML的に書式がおかしい。
commandというキーにmv ~~~という値をセットいている以上、そのサブキー(なんて言うのが正しい?)は書けない。

あとドキュメントにも書かれている通り、以下のようにワイルドカードも使用可能。
shellの方には書かれてないけど、shellでもワイルドカードは使えた。

  - name: mv file
    shell: 
      cmd: mv /tmp/zzz-src /tmp/zzz-dest
      removes: /tmp/zzz-sr*

A filename or (since 2.0) glob pattern

creates

  - name: mv file
    command:
      cmd: mv /tmp/zzz-src /tmp/zzz-dest
      creates: /tmp/zzz-dest

これは、/tmp/zzz-destが作成済みであれば実行されない(okになる)

ok: [localhost] => changed=false
  cmd:
  - mv
  - /tmp/zzz-src
  - /tmp/zzz-dest
  rc: 0
  stdout: skipped, since /tmp/zzz-dest exists
  stdout_lines: <omitted>

removes

  - name: mv file
    command:
      cmd: mv /tmp/zzz-src /tmp/zzz-dest
      removes: /tmp/zzz-src

removesを使うと逆で、/tmp/zzz-srcが無い場合は実行されない

ok: [localhost] => changed=false
  cmd:
  - mv
  - /tmp/zzz-src
  - /tmp/zzz-dest
  rc: 0
  stdout: skipped, since /tmp/zzz-src does not exist
  stdout_lines: <omitted>

同時指定

両方していするとどうなるか。

  - name: mv file
    command:
      cmd: mv /tmp/zzz-src /tmp/zzz-dest
      creates: /tmp/zzz-dest
      removes: /tmp/zzz-src
# src dest 動作
1 ない ない removes: /tmp/zzz-srcの条件によりskip (1)
2 ある ない creates/removesの条件を満たさず、task動作
3 ない ある creates: /tmp/zzz-destの条件によりskip (2)
4 ある ある creates: /tmp/zzz-destの条件によりskip (2)
  1. stdout: skipped, since /tmp/zzz-src does not exist
  2. stdout: skipped, since /tmp/zzz-dest exists

#4 の動作を見る限り、内部処理でcreatesremovesに評価していると思われる。

というかソース見るとそうなってる。

github.com

Ansible的には「どちらかでも条件を満たせばskip (評価順はcreates->removes)」となる。(ANDではなくOR)

例: 「ファイルを移動する」をこれ使って簡易的にやりたいとき

srcファイルが無い場合

通常は「エラー」じゃなくて「何もしない」を期待すると思うので、基本的に removes: /tmp/zzz-src は大前提と考える。

これは #3 の場合でcreates未指定であっても、removes: /tmp/zzz-src を満たすので、「何もしない」動作になる。

destファイルが既にある場合

上記の表の#3/#4だが、#4の「srcファイルが存在する場合」の実行は要件によって以下の2パターンが考えられる。

  • destがあるなら無視
  • srcがあるならdestを上書き

srcがあっても無視

これは上記表の#4の動作の通り。
よって、creates/removes両方を指定する。

      cmd: mv /tmp/zzz-src /tmp/zzz-dest
      removes: /tmp/zzz-src
      creates: /tmp/zzz-dest

srcがあるならdestを上書き

上記表#4の条件時に、skipでなく実行させたいというパターン。
これはcreatesの定義を外せば要件を満たす。 createsを条件に使用している#3については、前述のsrcファイルが無い場合の通り、removesの条件で同じ要件を満たすので問題ない。
よって、removesのみ指定する。

      cmd: mv /tmp/zzz-src /tmp/zzz-dest
      removes: /tmp/zzz-src

この場合の動作は

# src dest 動作
1 ない ない removes: /tmp/zzz-srcの条件によりskip
2 ある ない removesの条件を満たさず、task実行
3 ない ある removes: /tmp/zzz-srcの条件によりskip
4 ある ある removesの条件を満たさず、task実行

(余談)srcとdestに差異がある場合は上書き

cmd: mvcreates/removesの組み合わせじゃ無理なのでcopyモジュールとか使うしかないかな?
この場合、「コピー」になるのでdestを上書きしてもsrcは残ったままなので消したい場合は工夫(changedの場合のみ消すとか)が必要だけど。


もし「createsremovesどっちがどの条件のときに動くのか動かないのかどっち?」と思った人は、Ansibleらしく「creates/reomovesの状態にする(その状態になってたら何もしない)」と覚えればOK