Red Hat CodeReady Containers(CRC)での自作イメージのデプロイ手順

# はじめに

この投稿では、自分のローカル環境に導入した[Red Hat CodeReady Containers(CRC)](https://developers.redhat.com/products/codeready-containers/overview)において、自分で用意したイメージをCRC上で動作させる手順について記載します。


CRCは、Red Hat OpenShift 4.x のminimal版をローカルの環境で稼働させることができるソフトウェアです。

※以下が公式ガイドになります。
[Getting Started Guid](https://code-ready.github.io/crc/)
[Product Documentation for Red Hat CodeReady Containers](https://access.redhat.com/documentation/en-us/red_hat_codeready_containers/)


要求されるスペックは非常に高いものの（4vCPU、8GBメモリ、35GBディスクのVMが必要）、OpenShiftを学習するうえで非常に便利なソフトウェアになっています。

自分のローカル環境にCRCを導入し、公開されているイメージをCRCで動作させるところまではすんなりできたのですが、（最終的には解決できたものの）いざ自分で用意したイメージを動作させようとすると詰まってしまったので、備忘録として記録することにします。

詰まった点は、**「CRCがレジストリからコンテナイメージをpullする際にエラーになる(ErrImagePullが発生する）」**という点でした。アクセス権限が無い、レジストリ側の証明書が自己証明書でinsecureであるなどの問題があり、試行錯誤の連続でした。

以下は最終的にうまくいった手順を記載します。

（CRC（OpenShift）は内部にレジストリを持ちますが、その内部レジストリを使用したケースではどうしてもうまくいかなかったため、もし手順をご存知の方がいらっしゃいましたらご教示ください）


# 動作環境

- マシン　：　MacBook Pro （16インチ, Late 2019）　（8コア、64GBメモリ）
- OS　　：　macOS Catalina　（10.15.3）
- CodeReady Containers 1.6.0+8ef676f
- Docker Desktop 2.2.0.5 (43884) 


# 用意したイメージをQuay.ioにpushし、CRCからpullするケース

[Quay.io](https://quay.io/)は、プライベートなDockerレジストリを提供するサービスで、現在はRed Hat社によって運営されています。以降は、Quay.ioのアカウントを保持していることを前提に記述します。

このケースのポイントは、レジストリからのイメージの取得の際にQuay.ioへの認証が必要ですので、そのためのSecretを作成するという点になります。

Kubernetesでは、[Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/)というドキュメントがあります。ここでは、Secretを作成し、Podのマニフェストファイル内で imagePullSecrets でそのSecretを指定することでpullできるようにしています。

OpenShiftでは、[5.4.2. Pod が他のセキュリティー保護されたレジストリーからイメージを参照できるようにする設定](https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.3/html/images/using-image-pull-secrets)というドキュメントに記載があります。Secretを作成するところは素のKubernetesと同じですが、これをprojectのdefaultサービスアカウントと紐付けます。

以下手順です。


## 1.　Quay.io にログインし、Docker credentialを入手する

- Quay.ioにログイン後、画面右上のアカウント名 -> Account Settingsをクリック。
- 「CLI Password:	Generate Encrypted Password」の「Generate Encrypted Password」をクリック。
- パスワード入力が求められるので、Quay.ioのパスワードを入力してVerify
- 「Docker Configuration」から、クレデンシャルのJSONファイルをダウンロードする


## 2.　project を作成し、そのprojectに移動する

```
oc login -u developer -p <パスワード> https://api.crc.testing:6443
oc new-project sample1
oc project sample1
```


## 3.　JSONファイルを使用し、Secretを作成する

CRCがQuay.ioからイメージを取得する際、認証のためのSecretが必要。
上記で作成したプロジェクトにSecretを作成する。

```
oc create secret generic quayio \
 --from-file .dockerconfigjson=<1で入手したJSONファイル> \
 --type kubernetes.io/dockerconfigjson
```


## 4.　作成したSecretを、project の default サービスアカウントに関連付ける

```
oc secrets link default quayio --for pull
```


## 5.　Quay.io にDockerイメージをpushする

ここでは、Quay.io にある既存の公開イメージを取得し、それを個人のリポジトリにpushして、それを自作イメージと見立てます。

```
# Quay.ioにログイン
docker login quay.io

# イメージを取得
docker pull quay.io/redhattraining/hello-world-nginx

# タグ付けし、個人のリポジトリにpush
docker tag quay.io/redhattraining/hello-world-nginx quay.io/<Quay.ioのアカウント>/hello-world-nginx-test
docker push quay.io/<Quay.ioのアカウント>/hello-world-nginx-test
```


## 6.　ImageStreamを作成する

pushしたイメージを参照するImageStreamを作成します。

```
oc import-image hello-world-nginx-test --confirm --insecure --from quay.io/<Quay.ioのアカウント>/hello-world-nginx-test
```

## 7.　アプリを作成・公開する

oc new-appでアプリを作成し、oc exposeで外部からアクセス可能にします。

```
# 作成したImageStreamからアプリを作成
oc new-app --name hello-world-nginx-test -i hello-world-nginx-test

# Routeを作成し、Nginxを外部に公開する
oc expose svc/hello-world-nginx-test
```

## 8.　稼働確認

CRCの管理コンソールでアプリのURLを確認し、公開されたアプリにアクセスして稼働を確認します。




# ローカル環境にレジストリを用意し、そこにイメージをpushし、CRCからpullするケース

こちらのケースでは、自分のローカル環境にレジストリを立て、それをCRCの外部レジストリとして利用します。ここではDockerが公開している[Docker Registry](https://docs.docker.com/registry/)をレジストリとして使用します。また、HTTPSでのアクセスを可能とするため、自己証明書も用意・設定します。


## HTTPS対応のDocker Registryの構築

### 1.　Docker Registryの certsファイル用、data用のディレクトリ作成

自己証明書を保存するためのディレクトリ、レジストリのデータの永続化のためのディレクトリを作成します。

```
❯ pwd
/Users/xxxx/docker/registry

mkdir certs
mkdir data
```

### 2.　certsファイルの作成

上記で作成したcerts用のディレクトリに自己証明書を作成します。

```
cd certs
openssl req -newkey rsa:2048 -nodes -keyout domain.key -x509 -days 365 -out domain.crt
```


### 3.　Docker Registryの起動

ボリュームとして上記で作成したcertsディレクトリ、dataディレクトリを指定して、Docker Registryコンテナを起動します。ポート5001で公開するものとします。

```
❯ pwd
/Users/xxxx/docker/registry

# 5001ポートで公開
docker run -d \
 --restart=always \
 --name registry \
 -v `pwd`/certs:/certs \
 -v `pwd`/data:/var/lib/registry \
 -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
 -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
 -e REGISTRY_STORAGE_DELETE_ENABLED=True \
 -p 5001:443 \
 registry:2.7.1
```


### 4.　稼働確認

ブラウザで以下にアクセスし、稼働を確認します。
https://localhost:5001/v2/_catalog



## CRCへのデプロイ

ローカルのDocker Registryは、Quay.ioを使用する場合と異なり、自己証明書のため、CRCに対してinsecureRegistryの設定が必要です。

参考：https://github.com/code-ready/crc/wiki/Adding-an-insecure-registry


### 1.　kubeadminでCRCにログイン

```
oc login -u kubeadmin -p <kubeadmin_password> https://api.crc.testing:6443
```

### 2.　image.config.openshift.io リソースにpatch適用。insecureRegistriesに、ローカルのDocker Registryを追加

CRCのVMから見たときのホストOSは192.168.64.1で、ローカルのDocker Registryは、CRCからは192.168.64.1:5001でアクセスできます（ポートは上記で設定した値）。

```
oc patch --type=merge --patch='{
  "spec": {
    "registrySources": {
      "insecureRegistries": [
        "192.168.64.1:5001"
      ]
    }
  }
}' image.config.openshift.io/cluster
```


### 3.　CRCのVMにログインし、 /etc/containers/registries.conf にinsecure registryとして登録


```
❯ crc ip
192.168.64.3

# 上記のcrc ipで取得したIPアドレスを指定し、sshアクセス
ssh -i ~/.crc/machines/crc/id_rsa -o StrictHostKeyChecking=no core@192.168.64.3


# 以下はCRCのVM上での作業

# CRCのVMの/etc/containers/registries.confを編集
$ sudo vi /etc/containers/registries.conf

# 以下を追記する
[[registry]]
  location = "192.168.64.1:5001"
  insecure = true
  blocked = false
  mirror-by-digest-only = false
  prefix = ""


# CRI-O、kubeletを再起動
$ sudo systemctl restart crio
$ sudo systemctl restart kubelet
$ exit
```

（なお、oc debug nodes/<ノード名> でCRCのVMにアクセスすることもできるが、viでの編集の際、編集位置がずれてうまく編集できなかった）


### 4.　project を作成し、そのprojectに移動する

```
oc login -u developer -p <パスワード> https://api.crc.testing:6443
oc new-project sample2
oc project sample2
```


### 5.　DockerイメージをローカルのDocker Registryにpush

Docker Registryの準備ができたので、Quay.ioのケースと同じように、公開されているイメージを取得し、自作のイメージと見立ててpushする。

```
# Quay.ioにログイン
docker login quay.io

# イメージを取得
docker pull quay.io/redhattraining/hello-world-nginx

# タグ付けし、Docker Registryにpush
docker tag quay.io/redhattraining/hello-world-nginx 192.168.64.1:5001/hello-world-nginx-test-2
docker push 192.168.64.1:5001/hello-world-nginx-test-2
```

### 6.　ImageStreamを作成する

pushしたイメージを参照するImageStreamを作成します。

```
oc import-image hello-world-nginx-test-2 --confirm --insecure --from 192.168.64.1:5001/hello-world-nginx-test-2
```

### 7.　アプリを作成・公開する

oc new-appでアプリを作成し、oc exposeで外部からアクセス可能にします。

```
# 作成したImageStreamからアプリを作成
oc new-app --name hello-world-nginx-test-2 -i hello-world-nginx-test-2

# Routeを作成し、Nginxを外部に公開する
oc expose svc/hello-world-nginx-test-2
```


## 8.　稼働確認

CRCの管理コンソールでアプリのURLを確認し、公開されたアプリにアクセスして稼働を確認します。