はじめに
Red Hat OpenShift on IBM Cloudでは、コンテナレジストリとしてIBM Cloud Container Registryを使用するケースが多いと思います。ただ、Container Registryを使用できないケースでは、OpenShift内でデフォルトでセットアップされているOpenShift Container Registry(OCR)を使用することになります。
OCRは内部からのアクセスが可能であるものの、例えばローカルの端末でビルドしたイメージをpushするといったような外部からのアクセスができない状態になっています。
この記事では、OCRに外部からアクセス(push)できるように設定し、さらに、クラスター内でOCRからイメージをpullできるように設定する手順を紹介します。この記事の内容は、基本的に「IBM Cloudドキュメント:内部レジストリーのためのセキュアな外部経路のセットアップ」に基づいています。
前提環境
・Red Hat OpenShift on IBM Cloud (OpenShiftバージョン:4.10.22_1528)
・OpenShiftクラスターに対して、IBM Cloud IAMの「マネージャ」サービス役割を保持していること
内部レジストリに外部からpushできるようにする
openshift-image-registry プロジェクトに、image-registry
サービスが存在することを確認します。
❯ oc get svc -n openshift-image-registry
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
image-registry ClusterIP xxx.xxx.xx.xxx <none> 5000/TCP 6h33m
image-registry-operator ClusterIP None <none> 60000/TCP 6h50m
image-registry
サービスに対して、暗号化されたrouteを作成します。ここではreencrypt
(クライアント - route間で暗号化を一旦終端し、再度暗号化してroute - 内部レジストリ間もセキュアにする)を指定してrouteを作成します。
❯ oc create route reencrypt --service=image-registry -n openshift-image-registry
route.route.openshift.io/image-registry created
作成されたrouteに割り当てられたホスト名、ポートを確認します。
❯ oc get route image-registry -n openshift-image-registry
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
image-registry image-registry-openshift-image-registry.xxxxx.jp-tok.containers.appdomain.cloud image-registry 5000-tcp reencrypt None
作成したrouteをoc edit
で編集し、ロードバランスの方式をsource
に変更します。これにより、同じIPアドレスからのアクセスは同じPodに到達するようになります。
oc edit route image-registry -n openshift-image-registry
編集箇所は(コメントを含めて)10行目あたりで、metadata.annotations
にhaproxy.router.openshift.io/balance: source
の行を追加して保存します。
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: route.openshift.io/v1
kind: Route
metadata:
annotations:
openshift.io/host.generated: "true"
haproxy.router.openshift.io/balance: source # 左記の内容を追加する
以上により外部から内部レジストリにアクセスできるようになったので、docker login
によりログインします。ホスト名・ポートは、上記のrouteで確認したホスト名・ポートを使用します。ユーザ名、パスワードは、OpenShiftへのログインユーザ、パスワードを使用します。
❯ docker login -u $(oc whoami) -p $(oc whoami -t) image-registry-openshift-image-registry.xxxxxxxxxxx.jp-tok.containers.appdomain.cloud
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded
ここでは、イメージをpushし、デプロイして稼働させるためのサンプルプロジェクトをsample
という名前で作成します。
❯ oc new-project sample
Now using project "sample" on server "https://c115-e.jp-tok.containers.cloud.ibm.com:30645".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname
pushするイメージとしてnginxを使用します(--platform
オプションは、ローカル端末がM1 Mac(arm64)のために付けています。amd64のCPUの場合は不要です)。
❯ docker pull --platform linux/x86_64 nginx:latest
latest: Pulling from library/nginx
Digest: sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49
Status: Image is up to date for nginx:latest
docker.io/library/nginx:latest
OCRにpushするための準備として、docker tag
コマンドでタグを付けます。ホスト名の部分は作成したrouteで確認したホスト名です。ホスト名に続けて、/<プロジェクト名>(この例ではsample)/nginx:latest
を指定します。
❯ docker tag nginx:latest image-registry-openshift-image-registry.xxxxxxx.jp-tok.containers.appdomain.cloud/sample/nginx:latest
タグを付けたイメージをpushします。
❯ docker push image-registry-openshift-image-registry.xxxxxxx.jp-tok.containers.appdomain.cloud/sample/nginx:latest
The push refers to repository [image-registry-openshift-image-registry.xxxxxxx.jp-tok.containers.appdomain.cloud/sample/nginx]
b539cf60d7bb: Pushed
bdc7a32279cc: Pushed
f91d0987b144: Pushed
3a89c8160a43: Pushed
e3257a399753: Pushed
92a4e8a3140f: Pushed
latest: digest: sha256:f26fbadb0acab4a21ecb4e337a326907e61fbec36c9a9b52e725669d99ed1261 size: 1570
イメージをpushすると、sample
プロジェクトにImageStreamが作成されるため、それを確認します。
❯ oc get imagestream
NAME IMAGE REPOSITORY TAGS UPDATED
nginx image-registry.openshift-image-registry.svc:5000/sample/nginx latest 29 seconds ago
クラスターが内部レジストリからイメージをpullできるようにする
次に、pushしたイメージをpullできるように設定します。
現在のプロジェクトが先ほど作成したsample
であることを確認します。
❯ oc project
Using project "sample" on server "https://c115-e.jp-tok.containers.cloud.ibm.com:xxxxx".
default
サービスアカウントの詳細を表示し、Image pull secrets
で指定されているSecretを確認します。
❯ oc describe sa default
Name: default
Namespace: sample
Labels: <none>
Annotations: <none>
Image pull secrets: default-dockercfg-zzjd4
Mountable secrets: default-token-bqklv
default-dockercfg-zzjd4
Tokens: default-token-bqklv
default-token-wx8n9
Events: <none>
上記で確認したSecretをYAML形式で出力し、.dockercfg
の値を確認します。
❯ oc get secret default-dockercfg-zzjd4 -o yaml
apiVersion: v1
data:
.dockercfg:xxxxx
.dockercfg
の値はBase64でエンコードされているため、それをデコードします(echo
コマンドに渡しているのが.dockercfg
の値です)。デコードすることで、イメージをpullするために必要なusername、passwordを得ることができます。
echo "<ey...=>" | base64 -D
{"172.xx.xxx.xxx:5000":{"username":"serviceaccount","password":"ey......
上記で取得した「routeのホスト名」、「username」、「password」の値を用いて、内部レジストリ用の新たなImage Pull Secretを作成します。ここではinternal-registry
という名前のSecretを作成します。各オプションではそれぞれ以下を指定します。
-
--docker-server
: routeのホスト名+:5000
(ポート番号) -
--docker-username
: 上記のusernameの値 -
--docker-password
: 上記のpasswordの値 -
--docker-email
: 適当なメールアドレス(例:a@b.c
)
oc create secret image-registry internal-registry --namespace sample --docker-server image-registry-openshift-image-registry.xxxxxxx.jp-tok.containers.appdomain.cloud:5000 --docker-username serviceaccount --docker-password <eyJ...> --docker-email a@b.c
default
サービスアカウントに、上記で作成したImage Pull Secretを追加します。
❯ oc patch -n sample serviceaccount/default --type='json' -p='[{"op":"add","path":"/imagePullSecrets/-","value":{"name":"internal-registry"}}]'
serviceaccount/default patched
nginxのイメージでは、ポート80を使用するためにroot権限が必要になります。しかし、OpenShiftはセキュリティ上の理由からコンテナで設定されているユーザではなく、ランダムなUIDで実行するため、ポート80が使用できません。それを回避するため、anyuid
SCCをdefault
サービスアカウントに付与し、コンテナで設定したユーザでの実行を許可します。
❯ oc adm policy add-scc-to-user anyuid -z default
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:anyuid added: "default"
nginxコンテナのデプロイ
それではnginxコンテナをデプロイしてみます。
OpenShiftのWebコンソールにアクセスし、「Developer」パースペクティブを選択し、「追加」→「コンテナイメージ」をクリックします。
「内部レジストリーからのイメージストリームタグ」を選択し、プロジェクト、イメージストリーム、タグに、それぞれ「sample」、「nginx」、「latest」を指定します。
画面を下にスクロールし、他の項目はデフォルト値のままで「作成」ボタンをクリックします。