RHEL7のPodmanでOCP 4.11のOpenShift CLI (ocコマンド)を使用する


# 背景

OCP 4.11は、OpenShift CLI (ocコマンド)が、RHEL 7上でサポートされなくなりました。
(RHEL7でテストしたバイナリが提供されなくなった。)

- [OCP 4.11 Docs / リリースノート / 1. OpenShift Container Platform 4.11 リリースノート / 1.5. 非推奨および削除された機能 / 1.5.2. 削除された機能](https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.11/html-single/release_notes/index#ocp-4-11-oc-rhel-7)

> 1.5.2.1. OpenShift CLI (oc) の RHEL 7 サポートが削除される
> OpenShift CLI (oc) で Red Hat Enterprise Linux (RHEL) 7 を使用するためのサポートが削除されました。RHEL で OpenShift CLI (oc) を使用する場合は、RHEL 8 以降を使用する必要があります。


ですので、**これから新規に`OCP 4.11`を導入する人は、踏み台サーバーは最初から`RHEL8`にしておく必要**があります。

一方、**今まで`RHEL7`の踏み台サーバーを使用して`OCP 4.10`以前を導入していた人は、`OCP 4.11`にアップデートすると、`RHEL7`でサポートされる`OCP 4.11`の`oc`コマンドがなくなる**ので、詰んでしまいます。

ですので、基盤のポリシーなどの理由でOSが`RHEL7`しか使えないなどの場合はなんらかの方法を考える必要があります。



その場合のワークアラウンドとして、`RHEL7`のPodmanで`OCP 4.11`のOpenShift CLI (`oc`コマンド)を使用する方法が、以下のKnowledgeBaseに記載されていました。

- [KB / Managing the oc on RHEL 7 deprecation and support removal with OpenShift 4.11](https://access.redhat.com/articles/6968945)

(なお、新規に`OCP 4.11`を導入する際には、インストール時にocコマンドを使うため、その時点では上述のワークアラウンドは使えないので、踏み台サーバーは最初から`RHEL8`か`RHEL9`にしておく必要があると思われます。)


今回は、このKBの手順を実行してみた際のメモを記載しておきます。


# 前提

## OCP 4.11へのアップデート

アップデート前のOCP4.10の環境では、`RHEL7`の踏み台サーバーで`oc`コマンドを実行しているとします。

RHEL7の踏み台サーバーにはまだ`oc`クライアントはバージョンアップ前に`4.10.20`の`oc`のバイナリをPATHの切れている`/usr/localb/bin`に配置されている状態とします。
以下、cluster-admin権限のある管理者ユーザー(以下の例では`admin`)でOCPクラスターにログインした状態で作業を実施します。

```bash
[root@bastion-01 ~]# oc version
Client Version: 4.10.20
Server Version: 4.10.20
Kubernetes Version: v1.23.5+3afdacb
[root@bastion-01 ~]#
```

この状態でOCPコンソールで、`OCP 4.10`から`OCP 4.11`にアップデートしました。
> 検証時は`stable-4.11` Channelでは、OCP 4.10からOCP 4.11へのアップデートパスはなかったので、`fast-4.11` Channelでアップデートしました。
> (検証当時は`stable-4.11`では`4.11.2`が最新でしたが、`fast-4.11`でアップデートパスがあった`4.11.4`にアップデートしました。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332622/3ac56396-85a7-9341-321f-747cc53c909b.png)


OCPのバージョンと、ocコマンドのバージョンを確認します。
OCPクラスターは`4.11.4`になりましたが、`oc`コマンドはまだ`/usr/local/bin`に配置した`4.10.20`のものを実行しています。
```bash
[root@bastion-01 ~]# oc version
Client Version: 4.10.20
Server Version: 4.11.4
Kubernetes Version: v1.24.0+b62823b
[root@bastion-01 ~]#
```




# 手順

## OCP 4.11のCLIが使用できるコンテナイメージの取得 

OCP 4.11の内部レジストリに登録されているOCP 4.11のCLI(`oc`コマンド)が使用できるコンテナイメージのURLを確認します。

URLは、`default-route-openshift-image-registry.apps.<CLUSTER_NAME.BASE_DOMAIN>/openshift/cli`となりますが、以下のコマンドで確認できます。

```bash
export CLI_IMAGE=$(oc get is/cli -n openshift -o=jsonpath={.status.publicDockerImageRepository})
```

出力例
```bash
[root@bastion-01 ~]# export CLI_IMAGE=$(oc get is/cli -n openshift -o=jsonpath={.status.publicDockerImageRepository})
[root@bastion-01 ~]# echo ${CLI_IMAGE}
default-route-openshift-image-registry.apps.cluster-01.example.local/openshift/cli
[root@bastion-01 ~]#
```

踏み台サーバーのPodmanで上述のイメージを使用したコンテナを起動し、OCP 4.11の`oc`コマンドを実行します。


> (補足)  
> podman loginをした際の認証情報はデフォルトでは`${XDG_RUNTIME_DIR}/containers/auth.json`に保存されます。
> htpasswdのユーザーでoc loginし、そのユーザーでpodman loginをすると一定時間でtokenが切れます。
> そのため、ローカルにcliのイメージが削除されたりするとその都度podman loginが必要です。
> 毎回podman loginしないようにするには、内部レジストリに適切な権限を持つService Accountを作成してpodman loginをしておくことで、常時podmanでOCP内部レジストリのイメージをpushしたりpullしたりすることができます。
> もしくは、そこまでせずに、一旦ローカルにcliのイメージをpullしておき、ずっとローカルから削除しないように注意しておけば、毎回podman loginしなくても大丈夫です。


今回は`oc`コマンドの入ったコンテナを起動する前に、OCP内部レジストリからローカルにcliのイメージをpullしておくことにします。
(事前にローカルにpullしておかない場合は、初回実行時は、OCP内部レジストリからローカルにcliのイメージがpullされコンテナが実行されます。)


まず、cluster-adminロールのある管理者ユーザーでOCPクラスターにログインします。
```bash
[root@bastion-01 ~]# oc login -u admin -p <password> https://api.cluster-01.example.local:6443
Login successful.

You have access to 73 projects, the list has been suppressed. You can list all projects with 'oc projects'

Using project "debug".
[root@bastion-01 ~]#
```

次に、OCPの内部レジストリにpodmanでログインしておきます。
```bash
[root@bastion-01 ~]# REGISTRY=$(oc get route -n openshift-image-registry default-route -o jsonpath='{.spec.host}')
[root@bastion-01 ~]# echo ${REGISTRY}
default-route-openshift-image-registry.apps.cluster-01.example.local
[root@bastion-01 ~]#
[root@bastion-01 ~]# podman login -u $(oc whoami) -p $(oc whoami -t) ${REGISTRY}
Login Succeeded!
[root@bastion-01 ~]#
```

CLIが入ったコンテナイメージのImageStreamの名前を取得します。
```bash
[root@bastion-01 ~]# export CLI_IMAGE=$(oc get is/cli -n openshift -o=jsonpath={.status.publicDockerImageRepository})
[root@bastion-01 ~]# echo ${CLI_IMAGE}
default-route-openshift-image-registry.apps.cluster-01.example.local/openshift/cli
[root@bastion-01 ~]#
```

ローカルにはまだcliのイメージはありません。
```bash
[root@bastion-01 ~]# podman images | grep cli
[root@bastion-01 ~]#
```

OCPの内部レジストリからcliのイメージをローカルにpullします。
```bash
[root@bastion-01 ~]# podman pull $CLI_IMAGE
Trying to pull default-route-openshift-image-registry.apps.cluster-01.example.local/openshift/cli:latest...
Getting image source signatures
Copying blob f70d60810c69 done
Copying blob 9f93f50e4bd4 done
Copying blob 545277d80005 done
Copying blob a910d59a33a7 done
Copying blob 2020d93b45b0 done
Copying config e798432938 done
Writing manifest to image destination
Storing signatures
e798432938c498015adb053f3dd8974a7367d8ced390bd147707f0964dba6443
[root@bastion-01 ~]#
```

cliのイメージがローカルにpullされました。
```bash
[root@bastion-01 ~]# podman images | grep cli
default-route-openshift-image-registry.apps.cluster-01.example.local/openshift/cli   latest      e798432938c4  3 weeks ago   503 MB
[root@bastion-01 ~]#
```

## podmanのコンテナとして`OCP 4.11`の`oc`コマンドの実行


このイメージを使用したコンテナで`OCP 4.11`の`oc`コマンドを実行します。

- ocコマンドは特にKUBECONFIG環境変数や--kubeconfigをつけて実行はしていなかったので、Kubeconfigファイルは、`${HOME}/.kube/config`に作成されています。
- このローカルののKubeconfigファイルをコンテナの/kubeconfigにマウントして、コンテナの中から`OCP 4.11`の`oc`コマンドを実行するようにします。
- また、ocコマンド終了時にコンテナを削除するように`--rm`オプションもつけて実行します。

コマンド
```
podman run --rm -v ${HOME}/.kube/config:/kubeconfig:Z  -e KUBECONFIG=/kubeconfig  $CLI_IMAGE oc whoami
```

実際の実行例
`oc whoami`コマンドを実行してみると(先ほどの.kube/configを使用しているので)すでにOCPクラスタにログインされていることがわかります。
```bash
[root@bastion-01 ~]# podman run --rm -v ${HOME}/.kube/config:/kubeconfig:Z -e KUBECONFIG=/kubeconfig  $CLI_IMAGE oc whoami
admin
[root@bastion-01 ~]#
```

バージョンを確認すると、CLIのバージョンも`4.11.0`のものになっていることが分かります。
```
[root@bastion-01 ~]# podman run --rm -v ${HOME}/.kube/config:/kubeconfig:Z -e KUBECONFIG=/kubeconfig  $CLI_IMAGE oc version
Client Version: 4.11.0-202208291725.p0.g5e53738.assembly.stream-5e53738
Kustomize Version: v4.5.4
Server Version: 4.11.4
Kubernetes Version: v1.24.0+b62823b
[root@bastion-01 ~]#
```

このようにして`RHEL7`でも、`OCP 4.11`の`oc`コマンドをPodmanのコンテナとして実行することができました。


# 考慮点

この方法で`oc`コマンドを実行する際の考慮点です。

- この方法では、`oc`コマンドを使用する可能性のあるOSユーザー毎に、cliのイメージをpullしておく必要があります。
- OCPの更なるアップグレードをする場合は、OSユーザー毎に、podman loginして、最新のOCPバージョンのcliのイメージをpodman pullしておく必要があります。



# 補足

## ユーザーからの透過的なocコマンドの実行

先ほどの`podman run --rm xxxxx`コマンドを毎回打つのは大変なので、ユーザーは何も意識しないでコンテナで`oc`コマンド実行できるように、このコマンドをラップしたシェルなどを作ったりすると良いかと思います。


```bash
[root@bastion-01 ~]# vi oc
[root@bastion-01 ~]# chmod +x oc
[root@bastion-01 ~]#
[root@bastion-01 ~]# ls -l oc
-rwxr-xr-x. 1 root root 603  9月 20 14:44 oc
[root@bastion-01 ~]#
[root@bastion-01 ~]# cat oc
```

試しに以下のようなシェルを作成してみました。
```bash
#!/bin/bash

######################################################
# variables
######################################################

# Image name included OCP CLI (oc)
CLI_IMAGE=default-route-openshift-image-registry.apps.cluster-01.example.local/openshift/cli

# set KUBECONFIG
if [ -z ${KUBECONFIG} ]; then
export KUBECONFIG=${HOME}/.kube/config
fi

######################################################
# command
######################################################

exec podman run --rm \
     -v ${KUBECONFIG}:/kubeconfig:Z \
     -e KUBECONFIG=/kubeconfig \
     $CLI_IMAGE \
     oc "${@}"
```

このシェルで任意の`oc`コマンドが実行できるようになりました。
```bash
[root@bastion-01 ~]# ./oc version
Client Version: 4.11.0-202208291725.p0.g5e53738.assembly.stream-5e53738
Kustomize Version: v4.5.4
Server Version: 4.11.4
Kubernetes Version: v1.24.0+b62823b
[root@bastion-01 ~]#
[root@bastion-01 ~]# ./oc get node
NAME        STATUS   ROLES    AGE   VERSION
infra-01    Ready    infra    69d   v1.24.0+b62823b
infra-02    Ready    infra    69d   v1.24.0+b62823b
infra-03    Ready    infra    69d   v1.24.0+b62823b
master-01   Ready    master   69d   v1.24.0+b62823b
master-02   Ready    master   69d   v1.24.0+b62823b
master-03   Ready    master   69d   v1.24.0+b62823b
worker-01   Ready    worker   69d   v1.24.0+b62823b
worker-02   Ready    worker   69d   v1.24.0+b62823b
[root@bastion-01 ~]#
```

あとはこのシェルを`/usr/local/bin`などのPATHが切れたところに配置すれば、ユーザーからは意識しないで`oc`コマンドを使用することができるかなと思います。