k8sのpodをCompletedじゃなくrunning状態にしたいなら"tail -f /dev/null"をすればいいよって話

こんにちは
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

以前、私は以下の記事において自作したDockerImageを使ってpodをデプロイするとステータスが勝手にCompletedになってしまうのを何とかしたい的な事をツラツラと書きました。
結果としてpod内のプロセスが無いことが原因ですよねってことが判明し、下記記事ではpod内のコンテナでapache2のプロセスを稼動させることでCompletedになることを回避しました。しかしその回避策はかなり微妙。。。
しかも1回pod内のコンテナにアクセスして手動でやっているので、微妙さに拍車をかけています。いちいちアクセスするのはかなりだるい。。。
今回はその微妙な点を解消してみます。

https://qiita.com/ohtsuka-shota/items/97465435cfc0293d7eee

# tail -f /dev/nullをpod内のコンテナで実行させると良いっぽい。

どこで見たか忘れましたが、プロセスを意図的に残しておくために/dev/nullに対してtail -fをかけておくのが鉄板？の様です。少なくとも以前私がやったapache2をインストールして稼働させるより断然マシです。
/dev/nullについては以下を参照。Windowsで言うところのゴミ箱的なイメージで良いんじゃないでしょうか？厳密には違いますが。

https://e-words.jp/w/-dev-null.html

# kubectl runでpodデプロイ時に併せてコンテナ内でコマンドを実行させる方法

kubectl runコマンドのオプションで"--command"を指定してあげると良いっぽいです。
以下が実行結果になります。get podの出力結果としてrunningとなっていることが分かります。

```
root@sv-ohtsuka-k8s-master:~# kubectl run --restart=Never --image=shotaohtsuka/deb-ubuntu-image:latest testpod --command -- tail -f /dev/null 
pod/testpod created
root@sv-ohtsuka-k8s-master:~# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
testpod   1/1     Running   0          81s
```

pod内のコンテナ上のプロセスを見てみるとtail -fが動いているのが分かりますね。
コンテナからexitアウトしてもrunningのままとなっています。
良い感じです。
```
root@sv-ohtsuka-k8s-master:~# kubectl exec -it testpod -- /bin/bash
root@testpod:/# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 08:02 ?        00:00:00 tail -f /dev/null
root           7       0  0 08:04 pts/0    00:00:00 /bin/bash
root          18       7  0 08:04 pts/0    00:00:00 ps -ef
root@testpod:/# exit
exit

root@sv-ohtsuka-k8s-master:~# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
testpod   1/1     Running   0          2m6s
```

# yamlファイルでpodをデプロイする際に併せてコンテナ内でコマンドを実行させる方法

今回用意したyamlファイルは以下となります。
deb-ubuntuというpodを作成し、内部でdeb-ubuntu-containerコンテナをデプロイするという指示をざっくりしています。
コンテナはdocker hub上にある自作イメージである"shotaohtsuka/deb-ubuntu-image"を使用。
commandのところでコンテナを立ち上げる際に併せて実行するコマンドを指定しています。記載の仕方は一度わかると納得なのですが、最初は少し戸惑ってしまうかもしれません。"tail -f /dev/null"という記載の仕方だとpodがエラーを吐いてデプロイ出来ません。
"tail","-f","/dev/null"と要素を分解するように分けてあげましょう。
```
root@sv-ohtsuka-k8s-master:~/k8s_yaml# cat deb-ubuntu.yaml
apiVersion: v1
kind: Pod
metadata:
  name: deb-ubuntu
  labels:
    role: debug
spec:
  containers:
    - name: deb-ubuntu-container
      image: shotaohtsuka/deb-ubuntu-image
      command: ['tail', '-f', '/dev/null']
```

このyamlファイルを元にpodをデプロイしてみます。
上手く起動できていそうですね。
```
root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl create -f deb-ubuntu.yaml
pod/deb-ubuntu created
root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
deb-ubuntu   1/1     Running   0          63s
```

pod内のコンテナにアクセスしてみます。
問題なさそうです。
```
root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl exec -it deb-ubuntu -c deb-ubuntu-container -- /bin/bash
root@deb-ubuntu:/# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 08:51 ?        00:00:00 tail -f /dev/null
root           7       0  0 08:53 pts/0    00:00:00 /bin/bash
root          16       7  0 08:53 pts/0    00:00:00 ps -ef
```

雑ですがイメージです。
![kubernetes-ページ6.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/55474e72-53f5-3bdb-ba4e-18a3eb4144f0.png)

# 2023/5/13追記 yamlファイルへの記載の仕方について

上記ではspec.containers.commandにおいてまとめて書いていますが、他にも記載の仕方があるので追記し、まとめます。

## パターン1 commandに全部書いてしまう①
これは上記で書いているものと同じです。
```ubuntu-patt01.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-patt01
  labels:
    role: debug
spec:
  containers:
    - name: ubuntu-patt01
      image: ubuntu:latest
      command: [ "tail", "-f", "/dev/null" ]
```

## パターン2 commandに全部書いてしまう②
以下の様に書いてもパターン①と同様の意味となります。
```ubuntu-patt02.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-patt02
  labels:
    role: debug
spec:
  containers:
    - name: ubuntu-patt02
      image: ubuntu:latest
      command:
        - "tail"
        - "-f"
        - "/dev/null"
```

## パターン3 commandとargsに分けて書く
argsは"arguments"の略になります。
"arguments"は英語で"引数"の意味。(ちなみに"argument"だと"口論"の意になり全く異なるので注意)
tailコマンドの引数が"-f"と"/dev/null"だということを明示的に示しているようで、個人的にはこれが一番わかりやすいと思いました。
```ubuntu-patt03.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-patt03
  labels:
    role: debug
spec:
  containers:
    - name: ubuntu-patt03
      image: ubuntu:latest
      command: [ "tail" ]
      args: ["-f", "/dev/null" ]
```

どれでも同じと言えば同じなのですが、describeする時に出力が少し変わってきます。
```ubuntu-patt01.
Containers:
  ubuntu-patt01:
    Container ID:  containerd://86b23d6d5ee178076af2d40f1d6c76a76c02104c48528122ea3d4708adcae95f
    Image:         ubuntu:latest
    Image ID:      docker.io/library/ubuntu@sha256:dfd64a3b4296d8c9b62aa3309984f8620b98d87e47492599ee20739e8eb54fbf
    Port:          <none>
    Host Port:     <none>
    Command:
      tail
      -f
      /dev/null
```
```ubuntu-patt02.
Containers:
  ubuntu-patt02:
    Container ID:  containerd://af4fe19da11ebb001c634b299fb199d847a7b252efe4bba8c99710e7c02da4ab
    Image:         ubuntu:latest
    Image ID:      docker.io/library/ubuntu@sha256:dfd64a3b4296d8c9b62aa3309984f8620b98d87e47492599ee20739e8eb54fbf
    Port:          <none>
    Host Port:     <none>
    Command:
      tail
      -f
      /dev/null
```
```ubuntu-patt03.
Containers:
  ubuntu-patt03:
    Container ID:  containerd://529af4be73e216a3984e8c7e98bdb29262cdbef6b2be5be7ca74002723635146
    Image:         ubuntu:latest
    Image ID:      docker.io/library/ubuntu@sha256:dfd64a3b4296d8c9b62aa3309984f8620b98d87e47492599ee20739e8eb54fbf
    Port:          <none>
    Host Port:     <none>
    Command:
      tail
    Args:
      -f
      /dev/null
```