IBM Cloud Container Registryにイメージを登録するいくつかの方法

# 目的

IBM Cloud Container Registry（ICR）はIBM Cloudが提供するコンテナレジストリサービスです。ICRにイメージを登録する方法はいくつかありますが、最近IBM Cloud CLIを使った方法が非推奨になってしまったので、代替策も含めて紹介します。

# サンプルアプリ

当手順で使用するソースコードやDockerfileはGitHubで公開していますので、参考にしてください。

https://github.com/teruq-sample/sample-app

# 方法

## IBM Cloud Container Registry CLIを使用する（現在非推奨）

IBM Cloud Container Registry CLIはもともとイメージをビルドし登録する機能がありました。これを使うとローカルにdockerやpodmanをインストールしておく必要がなく楽でした。しかし残念ながら2021年9月からこの方式は非推奨となり、今後廃止されることになりました。現時点（2021年9月）では``--accept-deprecation``オプションを付与しないと動かなくなっています。

```
$ git pull
$ ibmcloud region-set jp.icr.io
$ ibmcloud cr build -t jp.icr.io/teruq/sample-app:1.0.0 .
失敗
The 'build' command is deprecated, you must specify the --accept-deprecation option to use this command. For more information see: https://www.ibm.com/cloud/blog/announcements/ibm-cloud-container-registry-deprecating-container-builds

$ ibmcloud cr build -t jp.icr.io/teruq/sample-app:1.0.0 --accept-deprecation .
警告: build コマンドは推奨されません。 詳しくは、次のページを参照してください: https://www.ibm.com/cloud/blog/announcements/ibm-cloud-container-registry-deprecating-container-builds

Sending build context to Docker daemon  194.7MB
（略）

OK
```

## DockerやPodmanを使用する

DockerやPodmanを使用する方法です。``ibmcloud cr login``を実行することでdockerやpodmanコマンドからICRを利用できるようになります。しかしこのためにそれぞれのツールをローカルにインストールする必要があります。

```
$ git pull
$ ibmcloud cr region-set jp.icr.io
$ ibmcloud cr login
$ docker build -t jp.icr.io/teruq/sample-app:1.0.0 .
$ docker push jp.icr.io/teruq/sample-app:1.0.0
```

## IBM Cloud Code Engineのビルド機能を使用する

少々変則的な使い方ですが、IBM Cloud Code Engineのビルド機能を使うことで、ICRへのイメージ登録を行うことができます。DockerやPodmanは不要です。また、Dockerfileやソースコードをあらかじめローカルにpullする必要がないところも楽です。

### プロジェクトの作成

Code Engineのプロジェクトを作成します。ビルドの種類ごとに分ける必要はないので1つあればよいでしょう。

```
$ ibmcloud ce project create --name image-build
プロジェクト 'image-build' を作成中...
プロジェクト「image-build」の ID は「72ed867c-5480-4c6c-b840-801fcf4bd419」です。
プロジェクト 'image-build' がアクティブになるのを待機しています...
プロジェクト 'image-build' の選択中。
OK
```

### アクセスシークレットの登録

ICRにアクセスするためのシークレットを登録します。これも1つあればよいでしょう。``--password``はICRに更新権限のあるAPIキーです。

```
$ ibmcloud ce registry create --name jp-icr-io-teruq --password ******** --server jp.icr.io
イメージ・レジストリーのアクセス・シークレット 'jp-icr-io-teruq' を作成中...
OK
```

### ビルドの作成

```
$ ibmcloud ce build create --name sample-app --image jp.icr.io/teruq/sample-app:1.0.0 --registry-secret jp-icr-io-teruq --source https://github.com/teruq-sample/sample-app.git --commit master --size small
ビルド 'sample-app' を作成中...
OK
```

### ビルドの実行

```
$ ibmcloud ce buildrun submit --build sample-app --wait
ビルド実行 'sample-app-run-210917-013517853'を送信中...
ビルド実行が完了するのを待機しています...
ビルド実行状況: '実行中'
ビルド実行が正常に完了しました。
ビルド実行の状況を確認するには、'ibmcloud ce buildrun get -n sample-app-run-210917-013517853' を実行してください。
OK
```

### ビルドログの確認

```
$ ibmcloud ce buildrun logs --buildrun sample-app-run-210917-013517853
（略）
#13 exporting to image
#13 pushing layers 2.8s done
#13 pushing manifest for jp.icr.io/teruq/sample-app:1.0.0@sha256:94ec1c570ac434dced550cba328229b57d5123fb83048d124a1df31497e97c3f
#13 pushing manifest for jp.icr.io/teruq/sample-app:1.0.0@sha256:94ec1c570ac434dced550cba328229b57d5123fb83048d124a1df31497e97c3f 0.4s done
#13 DONE 8.6s
```

## Red Hat OpenShift on IBM CloudのBuildを使用する

これも少々変則的ですが、Red Hat OpenShift on IBM Cloud（ROKS）のユーザーであれば、ROKSのBuildを使ってICRにイメージ登録することができます。

### レジストリシークレットの登録

ICRにイメージをプッシュ可能なシークレットを作成します。``--docker-password``はICRに更新権限のあるAPIキーです。

```
$ oc create secret docker-registry jp-icr-io-teruq --docker-server jp.icr.io --docker-username iamapikey --docker-password ******** --docker-email a@b.c
secret/jp-icr-io-teruq created
```
### サービスアカウントにレジストリシークレットをリンク

BuildConfigによるBuildコンテナがICRにイメージをプッシュできるよう、サービスアカウントにレジストリシークレットをリンクします。

```
$ oc secrets link builder jp-icr-io-teruq
```

### ビルドの実行

BuildCondigを作成して実行します。``--to-docker``を指定することで生成されたイメージを外部のレジストリに登録することを指定し、``--to``でICRを指定します。

```
$ oc new-build https://github.com/teruq-sample/sample-app.git --to-docker --to jp.icr.io/teruq/sample-app:1.0.0
--> Found image d0a3436 (2 months old) in image stream "default/open-liberty" under tag "21.0.0.7-full-java8-openj9" for "open-liberty:21.0.0.7-full-java8-openj9"

    * A Docker build using source code from https://github.com/teruq-sample/sample-app.git will be created
      * The resulting image will be pushed with Docker to "jp.icr.io/teruq/sample-app:1.0.0"
      * Use 'oc start-build' to trigger a new build

--> Creating resources with label build=sample-app ...
    buildconfig.build.openshift.io "sample-app" created
--> Success
```

### ビルドログの確認

ビルドログを確認します。

```
$ oc get pods
NAME                 READY   STATUS    RESTARTS   AGE
sample-app-1-build   1/1     Running   0          3s

$ oc logs -f sample-app-1-build
Pushing image jp.icr.io/teruq/sample-app:1.0.0 ...
Getting image source signatures
Copying blob sha256:3f0cfe4ac5fafbc38dd1ca8759c632b0dc2b7ad895a75900a6734b695d6b4097
（略）
Copying config sha256:3d40901987e5747876bd832628ea6dc4b7a6c28d47baad89ee221bf159f3f9cd
Writing manifest to image destination
Storing signatures
Successfully pushed jp.icr.io/teruq/sample-app@sha256:800ec73d5084ca3f485ee3c74c25632b21e9d78387f5d8bfe1f9bc87790f54f5
Push successful
```

## IBM Cloud ToolChainサービスを使用する

IBM CloudのCI/CD機能を使ってICRへイメージ登録することができます。

### ツールチェーンの作成

下記URLから、Build your ownツールチェーンを選択します。

> https://cloud.ibm.com/devops/create

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/ab749da2-75b8-ba3c-7898-9579a49e11e9.png)

名前をつけて作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/07ad49d3-a1d0-45e8-6499-9c084430a3e8.png)

ツールの追加を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/7d67b882-f630-9349-997c-26bd98b6bafd.png)

IBM CloudのGitLabを使用する場合は左を、github.comを使用する場合は右を選択します。今回は右のGitHubを使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/e3f284ff-c087-64d8-f960-f884428253dc.png)

初回の場合、GitHubの認証を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/c30bf62f-60a7-00b4-b3f1-9f46b46deaa6.png)

Authorize IBM-Cloudを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/9dc25789-b89a-ac41-c2d6-e2f8d4d19d8a.png)

リポジトリータイプを既存にし、リポジトリーURLを指定します。統合の作成を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/d7097e0f-0179-a1b3-541a-74fc267ea147.png)

再度ツールの追加を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/08f7643c-951f-4ed8-64a2-74d1c2ac4398.png)

Delivery Pipelineを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/ca901e93-4066-ee35-1d19-a010241be8d8.png)

名前を付けて作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/fe508ff7-24b8-c0ff-60a6-62fc536ca494.png)

Delivery Pipelineを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/43c94261-dfe4-56a5-5061-cf5ce61d3c06.png)

ステージの追加を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/1df6668b-6900-e360-f40d-b505b9cbe2f8.png)

入力タイプ、リポジトリー、ブランチを選択します。ステージトリガーは今回は手動にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/8a5ad5a1-8b47-8839-b666-635f28832543.png)

ジョブタブを選択し、ビルドジョブを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/fac98c9f-5693-7760-42f8-c6e788cfc875.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/7d911f89-4630-87f7-f97d-dbee5ee06c73.png)

ビルダータイプをContainer Registryにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/04ad1a9f-6e35-05d2-e4b5-4cefe7fd70e3.png)

名前空間、イメージ名を指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/d1087c0d-d131-83c2-5188-8d1cfda6320c.png)

ビルドスクリプトを2か所書き換えます。デフォルトだとイメージのタグがBUILD_NUMBERという連番になりますが、今回はバージョンを明示したいためです。

```
#!/bin/bash
echo -e "ビルド環境変数:"
echo "REGISTRY_URL=${REGISTRY_URL}"
echo "REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE}"
echo "IMAGE_NAME=${IMAGE_NAME}"
echo "BUILD_NUMBER=${BUILD_NUMBER}"
echo "IMAGE_TAG=${IMAGE_TAG}"  # 追加

# 環境変数についての詳細::
# https://cloud.ibm.com/docs/services/ContinuousDelivery?topic=ContinuousDelivery-deliverypipeline_environment#deliverypipeline_environment

# ビルド・オプションを確認または変更するには、次の項目を使用します::

echo -e "リポジトリー・ルートで Dockerfile を検査しています"
if [ -f Dockerfile ]; then 
   echo "Dockerfile が見つかりました"
else
    echo "Dockerfile が見つかりません"
    exit 1
fi

#ensure docker and buildkit are present if not already in current pipeline-base-image
which buildctl > /dev/null || (curl -fsSL https://github.com/moby/buildkit/releases/download/v0.8.0/buildkit-v0.8.0.linux-amd64.tar.gz | tar zxf - --strip-components=1 -C /usr/bin bin/buildctl)
which docker > /dev/null || (curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz | tar zxf - --strip-components=1 -C /usr/bin docker/docker)

FULL_IMAGE_NAME=$REGISTRY_URL/$REGISTRY_NAMESPACE/$IMAGE_NAME

#Classic pipeline Container Registry job requires PIPELINE_IMAGE_URL to be defined, so the next deploy job could access this value:
#export PIPELINE_IMAGE_URL="${FULL_IMAGE_NAME}:$BUILD_NUMBER"
export PIPELINE_IMAGE_URL="${FULL_IMAGE_NAME}:${IMAGE_TAG}"  # BUILD_NUMBERからIMAGE_TAGに変更

echo -e "コンテナー・イメージをビルドしています"
set -x
ibmcloud cr login
buildctl build --frontend dockerfile.v0 --local context=. --local dockerfile=. \
  --output type=image,name=${PIPELINE_IMAGE_URL},push=true \
  --export-cache type=registry,ref=${FULL_IMAGE_NAME}:buildcache \
  --import-cache type=registry,ref=${FULL_IMAGE_NAME}:buildcache
set +x
```

環境プロパティタブを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/1045d033-3341-629d-6054-96764e29d830.png)

IMAGE_TAGプロパティを追加します。最後に保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/bdebd92e-7a5d-f1e3-1399-f663a6a695eb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/fcf72dc8-15a6-d701-70a5-bc8ad0089253.png)

### ビルドの実行

▶ボタンを選択するとビルドが開始されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/fcf72dc8-15a6-d701-70a5-bc8ad0089253.png)

状況はログおよび履歴の表示で確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/0c98a447-8121-d17a-55e7-0742ce4a68ed.png)

# 比較

方法|Docker/Podmanが必要|ソースの置き場所
---|---|---
IBM Cloud Container Registry CLI|No|ローカル
Docker/Podman|Yes|ローカル
IBM Cloud Code Engineのビルド機能|No|Gitのみ
Red Hat OpenShift on IBM CloudのBuild|No|ローカルとGitどちらも可能
IBM Cloud ToolChainを使用|No|Gitのみ