OpenShift Image Registry  ＋ ONTAP S3 でシンプルにオンプレプライベートレジストリを始める

コンテナイメージを扱うときに セキュリティ上の懸念や環境の構成などの理由で オンプレ上のプライベートレジストリを用意したいケースもあるかと思います。
その際、レジストリのストレージ領域としてオブジェクトストレージを利用したい場合があるかと思いますが、オンプレ環境で信頼性の高いオブジェクトストレージをどう用意するかというのはひとつの考慮事項かと思います。

NetAppストレージでは ONTAP ver 9.8以降で[ONTAP Simple Storage Service （ S3 ）オブジェクトストレージサーバ](https://docs.netapp.com/ja-jp/ontap/s3-config/)（ONTAP S3）を有効にすることができるようになっています。ファイル・ブロックストレージとして利用していた環境で、追加のハードウェア/ソフトウェアを用意することなくシンプルにオブジェクトストレージの利用を開始することができます。

<br>
今回、オンプレでよく利用されるKubernetesディストリビューションであるOpenShiftで 標準で利用できるOpenShift Image Registryと組み合わせて、オンプレプライベートレジストリを構成してみたので、その手順を紹介したいと思います。


## 前提
以下の環境で試しています。 

- ONTAP 9.13.1P4
- OpenShift 4.13

## やってみること
ストレージにONTAP S3を構成して OpenShift Image Registry（以下OCR)の有効化し コンテナイメージのアップロードや利用ができることを確認してみる。


<br>

 1. ONTAP S3でBucket/アクセスユーザを準備
 2. OpenShift Image Registry（OCR)でONTAP S3をバックエンドオブジェクトストレージとして指定
 3. OpenShift Image Registry（OCR)の有効化
 4. 動作確認(OCRを利用してみる)

なお、OpenShift Cluster環境は展開済みの前提としています。


## 1. ONTAP S3でバケット/アクセスユーザを準備
OCR から ONTAP S3を利用するために、 ONTAPでバケットとアクセス用ユーザ（アクセスキー・シークレットキー）を準備します。

ONTAP S3を構成しているONTAPクラスタにアクセスして作業を実施します。

なお、ONTAP S3の作業は [System Manager](https://docs.netapp.com/ja-jp/ontap/concept_administration_overview.html)からWeb GUIの画面で実施でも可能ですが、今回はCLIで実施しています。作業に際しては、ONTAP S3用のSVM名はsvm48h、S3アクセス用のLIF名はlif_data_svm48h、作成するバケット名はs48bucketとして実施しています。

<BR>

ONTAP S3を新規に構成する場合は、こちらの手順ではなく [別記事](https://qiita.com/yoihoka/items/245eececf6c659b5c311) でAnsibleを利用した構成手順を紹介していますのでそちらを参考にしてください。別記事の作業を実施した場合、ここで手動で作成しているバケット/ユーザ等はAnsibleで自動で作成されます。手動作成は不要になりますので その場合は確認作業のみ実施してください。


#### 1-1. LIF（IPアドレス）の確認
ONTAP S3用のLIF情報からS3 Dataアクセス用のIPアドレスを確認します。
```shell:
soc-ontap2-01::> network interface show -vserver svm48h
            Logical    Status     Network            Current       Current Is
Vserver     Interface  Admin/Oper Address/Mask       Node          Port    Home
----------- ---------- ---------- ------------------ ------------- ------- ----
svm48h
            lif_data_svm48h
                         up/up    10.128.211.49/24   soc-ontap2-01-01
                                                                   e0a     true
            lif_mgmt_svm48h
                         up/up    10.128.211.48/24   soc-ontap2-01-01
                                                                   e0a     true
2 entries were displayed.

soc-ontap2-01::>
```
今回 Dataアクセス用LIFはlif_data_svm48hなので、IPアドレスは10.128.211.49となります。

#### 1-2. バケットの作成
OCRへアップロードされるイメージデータ等を配置するためのバケットを新規に作成します。
```shell:
soc-ontap2-01::>  object-store-server bucket create -vserver svm48h -bucket s48bucket -type s3 -size 200G
  (vserver object-store-server bucket create)
[Job 2259] Job succeeded: Successful

soc-ontap2-01::> object-store-server bucket show　-bucket s48bucket
  (vserver object-store-server bucket show)
Vserver     Bucket          Type     Volume            Size       Encryption Role       NAS Path
----------- --------------- -------- ----------------- ---------- ---------- ---------- ----------
svm48h      s48bucket       s3       fg_oss_1706227514 200GB      false      standalone -

soc-ontap2-01::> 
```
新規バケット s48bucket が作成されました。

#### 1-3. アクセス用ユーザ作成
ONTAP S3へアクセスするためのユーザを作成し、アクセスキーとシークレットキーを確認します。あわせてアクセス許可ポリシーを作成してグループで関連付けします。
```shell:
soc-ontap2-01::> object-store-server user create -vserver svm48h -user s48bucket_user1
  (vserver object-store-server user create)

soc-ontap2-01::> set advanced

Warning: These advanced commands are potentially dangerous; use them only when directed to do so by NetApp personnel.
Do you want to continue? {y|n}: y

soc-ontap2-01::*> object-store-server user show -vserver svm48h -user s48bucket_user1
  (vserver object-store-server user show)

                               Vserver Name: svm48h
              Object Store Server User Name: s48bucket_user1
                Object Store Server User ID: 4
       Object Store Server User Description:
Access Key for the Object Store Server User: ACCESSKEYXXXXXXXXXX
Secret Key for the Object Store Server User: SECRETKEYXXXXXXXXXXXXXXXXXXXXXX

soc-ontap2-01::*> set admin
soc-ontap2-01::> object-store-server policy create -vserver svm48h -policy s48bucket_policy
soc-ontap2-01::> object-store-server policy show -policy s48bucket_policy
  (vserver object-store-server policy show)
Vserver     Name               Is Read-Only Comment
----------- ------------------ ------------ ----------------
svm48h    s48bucket_policy   false

soc-ontap2-01::> object-store-server policy add-statement -vserver svm48h -policy s48bucket_policy -effect allow -actions * -resource s48bucket,s48bucket/*
  (vserver object-store-server policy add-statement)

soc-ontap2-01::> object-store-server policy show-statements -vserver svm48h -policy s48bucket_policy
  (vserver object-store-server policy show-statements)
Vserver   Policy       Index  Effect Actions          Resources
--------- ------------ ------ ------ ---------------- -----------------
svm48h
          s48bucket_policy  1 allow  *                s48bucket,
                                                      s48bucket/*

soc-ontap2-01::> object-store-server group create -vserver svm48h -name s48bucket_group -users s48bucket_user1 -policies s48bucket_policy
  (vserver object-store-server group create)

soc-ontap2-01::> object-store-server group show -name s48bucket_group
  (vserver object-store-server group show)
Vserver     Group ID  Group Name     Users            Policies
----------- --------- -------------- ---------------- -------------------
svm48h              1  s48bucket_group
                                     s48bucket_user1  s48bucket_policy

soc-ontap2-01::>
```
ONTAP S3アクセス用ユーザを作成しました。
アクセス許可の設定も実施したのでこのユーザに紐づくAccessKey、SecretKeyをつかってONTAP S3のバケットs48bucketへアクセスできます。


## 2. OpenShift Image Registry（OCR)でONTAP S3をバックエンドオブジェクトストレージとして指定
次に、ONTAP S3 を OCRへアップロードされるコンテナイメージを保存するバックエンドストレージとして利用するために、OCRのconfigへの設定追加と新規Secretの設定を実施します。

OpenShiftクラスタ に 接続できる環境から作業を実施します。

#### 2-1. ONTAP S3 アクセス情報を設定
OCRのconfigに ストレージとしてONTAP S3のバケット名とアクセス情報を設定します。
今回はIPアドレスをそのまま指定しています。


```shell:
$ oc edit configs.imageregistry.operator.openshift.io/cluster
→ 以下のようにspec.storage部分を更新・追記
---
  storage:
    managementState: Unmanaged
    s3:
      bucket: s48bucket
      region: dummyregion
      regionEndpoint: http://10.128.211.49/
---
```
#### 2-2.  ONTAP S3のユーザ情報を設定
OCR の Namespace(openshift-image-registry) の Secret として、ONTAP S3へのアクセスユーザのAccessKeyとSecretKey情報を設定します。

```shell:
$ oc create secret generic image-registry-private-configuration-user --from-literal=REGISTRY_STORAGE_S3_ACCESSKEY=ACCESSKEYXXXXXXXXXX --from-literal=REGISTRY_STORAGE_S3_SECRETKEY=SECRETKEYXXXXXXXXXXXXXXXXXXXXXX --namespace openshift-image-registry
```

これで、OCRからONTAP S3へアクセスするための準備が整いました。

## 3. OpenShift Image Registry（OCR)の有効化
OCRを有効化するため Image Registry Operatorのconfigで StatusをManagedに更新します。

OpenShiftクラスタ に 接続できる環境から以下コマンドを実行してStatusをManagedに更新します。

```shell:
$ oc patch configs.imageregistry.operator.openshift.io cluster --type merge --patch '{"spec":{"managementState":"Managed"}}'
config.imageregistry.operator.openshift.io/cluster patched
$ oc get configs.imageregistry.operator.openshift.io -o yaml | grep managementState
     managementState: Managed
```

設定完了後、image-registryが起動することを確認します。

```shell:
$ oc -n openshift-image-registry get pod
NAME                                               READY   STATUS      RESTARTS      AGE
cluster-image-registry-operator-7447c6f595-wm8n9   1/1     Running     2 (48d ago)   104d
image-pruner-28562400-zhmp5                        0/1     Completed   0             2d23h
image-pruner-28563840-mm2mc                        0/1     Completed   0             47h
image-pruner-28565280-wxcsh                        0/1     Completed   0             23h
image-registry-54774c8957-tbff8                    1/1     Running     0             58s
node-ca-5vf54                                      1/1     Running     0             104d
node-ca-9cp9h                                      1/1     Running     0             104d
node-ca-dzbjg                                      1/1     Running     1             104d
node-ca-fq4bt                                      1/1     Running     1             104d
node-ca-gg8zz                                      1/1     Running     0             90d
node-ca-lcjcw                                      1/1     Running     0             104d
node-ca-th24l                                      1/1     Running     1             104d
$ oc -n openshift-image-registry get deploy
NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
cluster-image-registry-operator   1/1     1            1           104d
image-registry                    1/1     1            1           58s
$ 
```

これで OCR による レジストリサービス の提供が開始されました。
コンテナイメージのデータは OCR を経由して ONTAP S3 バケットに 保存されアクセスされます。


## 4. 動作確認：
今回構成した OCR による レジストリサービスを利用してみます。

#### 4-1. コンテナイメージ アップロード：
OpenshiftクラスタのWorker NodeからOCRにアクセスして、イメージをPushできることを確認してみます。

OpenShiftクラスタ に 接続できる環境から Worker Nodeにアクセスします。
```shell:
$ oc get node
NAME                         STATUS   ROLES                  AGE    VERSION
ocp13-sfn95-master-0         Ready    control-plane,master   104d   v1.26.5+7a891f0
ocp13-sfn95-master-1         Ready    control-plane,master   104d   v1.26.5+7a891f0
ocp13-sfn95-master-2         Ready    control-plane,master   104d   v1.26.5+7a891f0
ocp13-sfn95-worker-0-ctxmj   Ready    worker                 104d   v1.26.5+7a891f0
ocp13-sfn95-worker-0-gm5s5   Ready    worker                 104d   v1.26.5+7a891f0
ocp13-sfn95-worker-0-nqwrs   Ready    worker                 104d   v1.26.5+7a891f0
ocp13-sfn95-worker-0-rhczr   Ready    worker                 90d    v1.26.5+7a891f0
$ oc debug node/ocp13-sfn95-worker-0-ctxmj
Temporary namespace openshift-debug-j86xt is created for debugging node...
Starting pod/ocp13-sfn95-worker-0-ctxmj-debug ...
To use host binaries, run `chroot /host`
Pod IP: 10.128.211.177
If you don't see a command prompt, try pressing enter.
sh-4.4# 
```

Worker Node上から OCR にアクセスします。

OCR を OpenShiftクラスタから利用するためサーバ名"image-registry.openshift-image-registry.svc:5000"でアクセスします。

```shell:
sh-4.4# chroot /host
sh-5.1# oc login -u kubeadmin -p XXXXXXXXXXXXXXXXXXX https://api-ocp13-green-lab:6443
WARNING: Using insecure TLS client config. Setting this option is not supported!

Login successful.

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

Using project "default".
sh-5.1# 
sh-5.1# HOST=image-registry.openshift-image-registry.svc:5000
sh-5.1# 
sh-5.1# podman login -u kubeadmin -p $(oc whoami -t) $HOST
Login Succeeded!
```

OCRへコンテナイメージ を アップロードしてみます。
今回は ubuntu のイメージを取得してタグ付けし、OCRへアップロードします。

```shell:
sh-5.1# podman pull ubuntu
Resolved "ubuntu" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull docker.io/library/ubuntu:latest...
Getting image source signatures
Copying blob 3c645031de29 done
Copying config 7af9ba4f0a done
Writing manifest to image destination
Storing signatures
7af9ba4f0a47d9bc8b1ffa492c6b0276476f1889cf4e699fba2236924e5932ed
sh-5.1# 
sh-5.1# podman tag ubuntu $HOST/ns01/ubuntu:latest
sh-5.1# 
sh-5.1# podman push $HOST/ns01/ubuntu:latest
Getting image source signatures
Copying blob e0a9f5911802 done
Copying config 7af9ba4f0a done
Writing manifest to image destination
Storing signatures
sh-5.1# 
```

OCRへアップロードしたコンテナイメージを利用できるか確認してみます。
コンテナを起動してアクセスし、OS情報を確認してみます。

```shell:
sh-5.1# podman run -it $HOST/ns01/ubuntu:latest
root@b9e207264947:/# 
root@b9e207264947:/# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
root@b9e207264947:/# exit
exit
sh-5.1# exit
exit
sh-4.4# exit
exit

Removing debug pod ...
Temporary namespace openshift-debug-j86xt was removed.
$
```
OCRへ コンテナイメージをアップロード、またアップロードしたイメージを利用できることを確認しました。


#### 4-2. Podのイメージとして利用
次に、4-1でアップロードしたイメージを利用するPodをOpenShiftクラスタにデプロイしてみます。

OpenShiftクラスタ に 接続できる環境から以下の作業を実施します。

```shell:
$ cat <<EOF>> ns01pod.yaml
kind: Pod
apiVersion: v1
metadata:
  name: ubuntu01
  namespace: ns01
spec:
  containers:
  - image: image-registry.openshift-image-registry.svc:5000/ns01/ubuntu
    name: ubuntu01
    command:
    - "/bin/sh"
    - "-c"
    - "while true; do sleep 1; done"
EOF
$ oc apply -f ns01pod.yaml
Warning: would violate PodSecurity "restricted:v1.24": allowPrivilegeEscalation != false (container "ubuntu01" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "ubuntu01" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "ubuntu01" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "ubuntu01" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
pod/ubuntu01 created
$ oc -n ns01 get pod
NAME       READY   STATUS    RESTARTS   AGE
ubuntu01   1/1     Running   0          5s
$ oc -n ns01 exec -it ubuntu01 -- bash
root@ubuntu01:/#
root@ubuntu01:/# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
root@ubuntu01:/# exit
exit
$ 
```
OCRにあるイメージを利用して OpenShiftクラスタ　に　Pod　をデプロイできることを確認しました。

#### 4-3. ONTAP S3のバケットを確認
アップロードしたコンテナイメージがONTAP S3 の バケット上に配置されていることを確認してみます。

今回はAWS CLIを利用し、プロファイル情報にONTAP S3アクセス用のAccessKey/SecretKeyを設定してバケット情報を確認してみます。

なお、AWS CLIのインストール手順などについては、[AWSのサイト](!https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)を参照ください。

```shell:
$ aws configure --profile ontap_s48bucket_user1
AWS Access Key ID [None]: ACCESSKEYXXXXXXXXXX
AWS Secret Access Key [None]: SECRETKEYXXXXXXXXXXXXXXXXXXXXXX
Default region name [None]:
Default output format [None]:
$ aws s3 ls s3://s48bucket --endpoint-url http://10.128.211.49/ --no-verify-ssl --profile ontap_s48bucket_user1 --recursive|grep ubuntu
2024-04-24 19:13:19         71 docker/registry/v2/repositories/ns01/ubuntu/_layers/sha256/2ce11891398c80721baec016ec69d1f7b0cb37fa31d906832199ddf787ef7603/link
2024-04-24 19:13:20         71 docker/registry/v2/repositories/ns01/ubuntu/_layers/sha256/7af9ba4f0a47d9bc8b1ffa492c6b0276476f1889cf4e699fba2236924e5932ed/link
2024-04-24 19:13:20         71 docker/registry/v2/repositories/ns01/ubuntu/_manifests/revisions/sha256/4d66089a2787cee74fdea03a67f93cd2500b9e4c1f3464abc127775a8850d7fc/link
$ aws s3 ls s3://s48bucket --endpoint-url http://10.128.211.49/ --no-verify-ssl --profile ontapselect_s48bucket_user1 --recursive|grep 2ce11891398c80721baec016ec69d1f7b0cb37fa31d906832199ddf787ef7603
2024-04-24 19:13:19   31524221 docker/registry/v2/blobs/sha256/2c/2ce11891398c80721baec016ec69d1f7b0cb37fa31d906832199ddf787ef7603/data
2024-04-24 19:13:19         71 docker/registry/v2/repositories/ns01/ubuntu/_layers/sha256/2ce11891398c80721baec016ec69d1f7b0cb37fa31d906832199ddf787ef7603/link
$ aws s3 ls s3://s48bucket --endpoint-url http://10.128.211.49/ --no-verify-ssl --profile ontapselect_s48bucket_user1 --recursive|grep 7af9ba4f0a47d9bc8b1ffa492c6b0276476f1889cf4e699fba2236924e5932ed
2024-04-24 19:13:20       2297 docker/registry/v2/blobs/sha256/7a/7af9ba4f0a47d9bc8b1ffa492c6b0276476f1889cf4e699fba2236924e5932ed/data
2024-04-24 19:13:20         71 docker/registry/v2/repositories/ns01/ubuntu/_layers/sha256/7af9ba4f0a47d9bc8b1ffa492c6b0276476f1889cf4e699fba2236924e5932ed/link
$ aws s3 ls s3://s48bucket --endpoint-url http://10.128.211.49/ --no-verify-ssl --profile ontapselect_s48bucket_user1 --recursive|grep 4d66089a2787cee74fdea03a67f93cd2500b9e4c1f3464abc127775a8850d7fc
2024-04-24 19:13:20        407 docker/registry/v2/blobs/sha256/4d/4d66089a2787cee74fdea03a67f93cd2500b9e4c1f3464abc127775a8850d7fc/data
2024-04-24 19:13:20         71 docker/registry/v2/repositories/ns01/ubuntu/_manifests/revisions/sha256/4d66089a2787cee74fdea03a67f93cd2500b9e4c1f3464abc127775a8850d7fc/link
[root@ansi-vm0m tmp]#

```
ONTAP S3のバケット上に4-1でアップロードしたubuntuコンテナイメージのデータが配置されていることを確認しました。

## まとめ。
OpenShift Image Registry（OCR) ＋ ONTAP S3 で オンプレプライベートレジストリ を構成し OpenShift クラスタ から レジストリ として利用できることを確認してみました。

ONTAP S3を利用することで、ONTAPストレージがある環境であればオンプレでも手軽にオブジェクトストレージを用意してレジストリのデータ配置場所として利用できます。

<BR>

今回はオブジェクトストレージを用意しましたが、代わりにストレージとしてファイル / ブロックを利用するため[ONTAP + Astra Tridentを利用する](https://docs.netapp.com/us-en/netapp-solutions/containers/rh-os-n_private_registry.html)ことも可能です。NFSで利用する際に大量のコンテナイメージを扱う環境で利用する場合は"nfsMountOptions: "lookupcache=pos"を指定してnegative dentryをキャッシュしないようにしておくと良いかと思います。
また、エンタープライズ環境でサービスの冗長性を考慮した構成が必要な場合はRed Hat Quay + ONTAP S3での構成を選択するなども可能です。

<BR>

こういった形で 用途や環境等にあわせて柔軟にファイル/ブロック/オブジェクトストレージを適用できるのもNetAppストレージ ONTAPの利点だと思います。