Kubernetes環境でOpenShiftのCLIコマンド"oc"を使ってみよう

本記事は[Kubernetes3 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kubernetes3)の24日目のエントリです🎄
Kubernetes環境でOpenShiftのコマンドである`oc`を使ってみようという内容(小ネタ)です。

# はじめに

Kubernetes環境でYAMLのマニフェストのベースを作る際に、例えばDeploymentであれば`kubectl create deployment`を使ったりすると思います。
本記事では、これに加えてRed HatがKubernetesを拡張してEnterpriseでも使いやすくするためにリリースしているOpenShiftのCLIツールである`oc`を使って、Kubernetes上でマニフェストの作成・更新を行ってみます。

動作は保証できないので本番環境では試さずに、試験環境でYAMLの作成を補助する程度にとどめてください。(免責事項)

# ocコマンド

`kubectl`はKubernetesのAPIサーバーと通信してKubernetesの様々な操作をするコマンドですが、`oc`も同じようにOpenShiftのAPIサーバーと通信して、OpenShiftの操作を行います。
OpenShiftはKubernetesを拡張したものなので、基本的にKubernetesでできることはOpenShiftでもできます。
逆に、OpenShiftでできることは、一部(Red Hatによって拡張された範囲)を除けばKubernetesでも可能です。
(※ Kubernetesの最新機能でOpenShiftがまだ追従できてないものは実行できないです)

つまり、Kubernetesでできる範囲(KubernetesのAPIサーバーが対応している範囲)であれば、`kubectl`ではできなくても`oc`ができることなら`oc`を使って操作可能となるようです。

図にするとこんなイメージです(箱の位置関係は機能の包含関係ですが、機能量ではないです)。

![oc on k8s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/509d3aa3-54bb-4f03-45e5-ba89ff618302.png)

## ocのインストール

Red Hat開発者アカウントがあれば、Cluster Managerのページ経由でダウンロードサイトへリンクされているので、動かしているプラットフォーム用のコマンドラインツールをダウンロードします。Linuxであれば`openshift-client-linux-(version).tar.gz`。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/4cad1fb6-0fed-e8d6-3ee7-1ab288c3c14e.png)

(実はこれCRCとかと同じダウンロードサイト上にあるので、ディレクトリ探せば普通に見えるんだけど、、リンク載せていいのかな？)

ダウンロードしたら環境変数`PATH`を設定します。

こんな感じ

```console
[zaki@minikube ~]$ minikube version
minikube version: v1.5.2
commit: 792dbf92a1de583fcee76f8791cff12e0c9440ad-dirty
[zaki@minikube ~]$ kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.3", GitCommit:"b3cbbae08ec52a7fc73d334838e18d17e8512749", GitTreeState:"clean", BuildDate:"2019-11-13T11:23:11Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
[zaki@minikube ~]$ oc version
Client Version: openshift-clients-4.2.2-201910250432-8-g98a84c61
Kubernetes Version: v1.16.2
```

`oc`も`kubectl`と同じく、`$HOME/.kube/config`にあるクラスタ・認証情報をもとに動作し、サブコマンドで指定された内容でAPIサーバーへRESTを実行するので、`kubectl`使える状態になっていれば、`oc`もそのまま使用できます。

`-v`でRESTの内容のデバッグログを出力すると分かりやすいです。

```console:kubectl_version
[zaki@minikube ~]$ kubectl version -v=7
I1222 18:40:29.063173   35725 loader.go:375] Config loaded from file:  /home/zaki/.kube/config
I1222 18:40:29.063670   35725 round_trippers.go:420] GET https://192.168.0.82:8443/version?timeout=32s
I1222 18:40:29.063677   35725 round_trippers.go:427] Request Headers:
I1222 18:40:29.063681   35725 round_trippers.go:431]     Accept: application/json, */*
I1222 18:40:29.063684   35725 round_trippers.go:431]     User-Agent: kubectl/v1.16.3 (linux/amd64) kubernetes/b3cbbae
I1222 18:40:29.068640   35725 round_trippers.go:446] Response Status: 200 OK in 4 milliseconds
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.3", GitCommit:"b3cbbae08ec52a7fc73d334838e18d17e8512749", GitTreeState:"clean", BuildDate:"2019-11-13T11:23:11Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
```

```console:oc_version
[zaki@minikube ~]$ oc version -v=7
I1222 18:37:58.684851   34421 loader.go:359] Config loaded from file /home/zaki/.kube/config
I1222 18:37:58.685490   34421 round_trippers.go:416] GET https://192.168.0.82:8443/version?timeout=32s
I1222 18:37:58.685497   34421 round_trippers.go:423] Request Headers:
I1222 18:37:58.685501   34421 round_trippers.go:426]     Accept: application/json, */*
I1222 18:37:58.685505   34421 round_trippers.go:426]     User-Agent: oc/v0.0.0 (linux/amd64) kubernetes/$Format
I1222 18:37:58.690516   34421 round_trippers.go:441] Response Status: 200 OK in 5 milliseconds
I1222 18:37:58.691340   34421 round_trippers.go:416] GET https://192.168.0.82:8443/apis/config.openshift.io/v1/clusteroperators/openshift-apiserver
I1222 18:37:58.691348   34421 round_trippers.go:423] Request Headers:
I1222 18:37:58.691352   34421 round_trippers.go:426]     User-Agent: oc/v0.0.0 (linux/amd64) kubernetes/$Format
I1222 18:37:58.691356   34421 round_trippers.go:426]     Accept: application/json, */*
I1222 18:37:58.691703   34421 round_trippers.go:441] Response Status: 404 Not Found in 0 milliseconds
I1222 18:37:58.691741   34421 version.go:130] OpenShift Version not found (must be logged in to cluster as admin): the server could not find the requested resource (get clusteroperators.config.openshift.io openshift-apiserver)
Client Version: openshift-clients-4.2.2-201910250432-8-g98a84c61
Kubernetes Version: v1.16.2
```

`kubectl`も`oc`も同じエンドポイントにGETしに行っています。
(`oc`は更にOpenShiftバージョン用のエンドポイントにアクセスに行っているが、これはAPIサーバー側が対応していないのでエラーになっている)

参考までにOpenShiftのAPIサーバーであればこんな感じ。

```console
I1222 18:48:15.401979    2467 round_trippers.go:420] GET https://api.crc.testing:6443/apis/config.openshift.io/v1/clusteroperators/openshift-apiserver
I1222 18:48:15.401987    2467 round_trippers.go:427] Request Headers:
I1222 18:48:15.401992    2467 round_trippers.go:431]     User-Agent: oc/v0.0.0 (linux/amd64) kubernetes/$Format
I1222 18:48:15.401999    2467 round_trippers.go:431]     Authorization: Bearer <masked>
I1222 18:48:15.402003    2467 round_trippers.go:431]     Accept: application/json, */*
I1222 18:48:15.403938    2467 round_trippers.go:446] Response Status: 200 OK in 1 milliseconds
Client Version: v4.3.0
Server Version: 4.2.2
```

# ocで可能なコマンド例

## oc set

Deploymentリソース等に設定を追加する`kubectl set`がありますが、`oc`ではできることが増えています。

```console:kubectl_set
[zaki@minikube ~]$ kubectl set
Configure application resources

 These commands help you make changes to existing application resources.

Available Commands:
  env            Update environment variables on a pod template
  image          Update image of a pod template
  resources      Update resource requests/limits on objects with pod templates
  selector       リソースのセレクターを設定する
  serviceaccount Update ServiceAccount of a resource
  subject        Update User, Group or ServiceAccount in a
RoleBinding/ClusterRoleBinding
```

```console:oc_set
[zaki@minikube ~]$ oc set
Configure application resources

 These commands help you make changes to existing application resources.

Usage:
  oc set COMMAND [flags]

Manage workloads:
  deployment-hook Update a deployment hook on a deployment config
  env             Update environment variables on a pod template
  image           Update image of a pod template
  probe           Update a probe on a pod template
  resources       Update resource requests/limits on objects with pod templates
  selector        Set the selector on a resource
  serviceaccount  Update ServiceAccount of a resource
  volumes         Update volumes on a pod template

Manage secrets and config:
  data            Update the data within a config map or secret
  build-secret    Update a build secret on a build config

Manage application flows:
  build-hook      Update a build hook on a build config
  image-lookup    Change how images are resolved when deploying applications
  triggers        Update the triggers on one or more objects

Manage load balancing:
  route-backends  Update the backends for a route

Manage authorization policy:
  subject         Update User, Group or ServiceAccount in a
RoleBinding/ClusterRoleBinding
```

この中でもOpenShift特有の機能はKubernetes環境では使えませんが、Kubernetesにもある機能は普通に使えます。
例えばこのあたり。

- `probe`: LivenessProbe/Readiness Probeのヘルスチェック設定
- `volumes`: PVなどのボリューム設定

コマンドは`--dry-run -o yaml`を付加すれば、実行はされずに必要なYAMLが出力されるので、作成済みマニフェストファイルへ内容を確認したうえでマージしても良いです。

```console
# /var/tmp/exampleへemptyDirを新規追加
$ oc set volume deploy/sockserv --add --mount-path=/var/tmp/example
info: Generated volume name: volume-k66pw
deployment.apps/sockserv volume updated
```

```yaml
    volumeMounts:
    - mountPath: /var/tmp/example
      name: volume-k66pw

[..snip..]

  volumes:
  - emptyDir: {}
    name: volume-k66pw
```

名前を指定してないのでボリューム名は自動で設定されます。

```console
# 作成済みのボリューム名volume-k66pwを削除
$ oc set volume deploy/sockserv --remove --name=volume-k66pw
deployment.apps/sockserv volume updated
```

```console
# 名前も指定する
$ oc set volume deploy/sockserv --add --mount-path=/var/tmp/example --name=example-vol
deployment.apps/sockserv volume updated
```

```console
# PVCを作成する
$ oc set volume deploy/sockserv --add --mount-path=/var/lib/zzz --name=mypv1 --type pvc --claim-size=20Gi
```

```console
# ボリュームの設定一覧を表示
$ oc set volume deploy/sockserv
deployments/sockserv
  empty directory as example-vol
    mounted at /var/tmp/example
  pvc/pvc-6qdfd (allocated 20GiB) as mypv1
    mounted at /var/lib/zzz
```

などなど。
probe設定についても同じように可能。`oc set probe --help`で実行例が表示されます。
あとは[アドカレ11日目に書いたこの辺](https://qiita.com/zaki-lknr/items/768d77363c3b566c4c19#probe%E3%81%AE%E8%BF%BD%E5%8A%A0)など…

## oc rsh

普段`$ kubectl exec -it pod-name sh`してるやつです。
必要なパラメタが少し減ります。

```console
# コンテナのシェルを起動
$ oc rsh sockserv-5f4995b598-m8ng5
#
```

実は`/bin/sh`が起動しています。

```console
# bashを指定してコンテナのシェルを起動
$ oc rsh sockserv-5f4995b598-m8ng5 bash
root@sockserv-5f4995b598-m8ng5:/#
```

`/bin/sh`が指定されているのは[この辺り](https://github.com/openshift/oc/blob/release-4.2/pkg/cli/rsh/rsh.go#L36)によるもの。

```go:rsh.go
const (
  RshRecommendedName = "rsh"
  DefaultShell       = "/bin/sh"
)
```

## oc rsync

要件として実行ノードとpod内の両方に`rsync`が必要ですが、既存の`kubectl cp`が`tar`を使ってコピーしているのに比べ、同期用の専用ツールである`rsync`を使うため、ファイルスタンプが保持されたり、変更の無い既存ファイルのコピーは除外されるなどの違いがあります。

```console:version確認
[zaki@minikube rsync-pod]$ rsync --version
rsync  version 3.1.2  protocol version 31
Copyright (C) 1996-2015 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 64-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes, prealloc

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.
[zaki@minikube rsync-pod]$
[zaki@minikube rsync-pod]$ oc rsh rsync-pod rsync --version
rsync  version 3.1.2  protocol version 31
Copyright (C) 1996-2015 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 64-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes, prealloc

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.
[zaki@minikube rsync-pod]$
```

```console:oc_rsync
[zaki@minikube rsync-pod]$ mkdir /var/tmp/pod-data
[zaki@minikube rsync-pod]$ oc rsync rsync-pod:/etc/apt /var/tmp/pod-data
receiving incremental file list
apt/
apt/sources.list
apt/apt.conf.d/
apt/apt.conf.d/01-vendor-ubuntu
apt/apt.conf.d/01autoremove
apt/apt.conf.d/01autoremove-kernels
apt/apt.conf.d/70debconf
apt/apt.conf.d/docker-autoremove-suggests
apt/apt.conf.d/docker-clean
apt/apt.conf.d/docker-gzip-indexes
apt/apt.conf.d/docker-no-languages
apt/auth.conf.d/
apt/preferences.d/
apt/sources.list.d/
apt/trusted.gpg.d/
apt/trusted.gpg.d/ubuntu-keyring-2012-archive.gpg
apt/trusted.gpg.d/ubuntu-keyring-2012-cdimage.gpg
apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg

sent 280 bytes  received 13,879 bytes  28,318.00 bytes/sec
total size is 12,870  speedup is 0.91
[zaki@minikube rsync-pod]$ ls -F /var/tmp/pod-data/apt/
apt.conf.d/  auth.conf.d/  preferences.d/  sources.list  sources.list.d/  trusted.gpg.d/
```

```console:oc_再実行
[zaki@minikube rsync-pod]$ oc rsync rsync-pod:/etc/apt /var/tmp/pod-data
receiving incremental file list

sent 30 bytes  received 475 bytes  1,010.00 bytes/sec
total size is 12,870  speedup is 25.49
```

## oc status

現在(または`-n`で指定)のnamespaceのdeploymentやpod,serviceの状態をリストします。

```console
$ oc status
In project default on server https://192.168.0.82:8443

svc/kubernetes - 10.96.0.1:443 -> 8443

svc/sockserv (all nodes) ports 8080, 8081
  deployment/sockserv deploys sockserv:v1.0
    deployment #8 running for about an hour - 1 pod
    deployment #7 deployed about an hour ago
    deployment #6 deployed 13 days ago
    deployment #5 deployed 2 hours ago
    deployment #3 deployed 13 days ago
    deployment #1 deployed 13 days ago


3 warnings, 1 info identified, use 'oc status --suggest' to see details.
```

---

# まとめ

`oc`コマンドを使ってKubernetesのAPIサーバーへアクセスする例をいくつか紹介してみました。

私がOpenShiftばかりでKubernetesとの差分をあまり把握できてないので、他に便利な使い方はもっとあるかもしれないですが、こんな感じにいろいろ動作します。
(ImageStreamやBuild系などのOpenShift独自のAPIは基本的に動作しませんが)
個人的には`oc whoami`が動かせたら良かったのですが、残念ながらKubernetesのAPIサーバーが対応してませんでした😂